@fabricorg/fabric-gen 0.4.1 → 0.6.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/CHANGELOG.md +91 -0
- package/README.md +5 -0
- package/dist/{chunk-CUNWMAA2.js → chunk-4QFNFERM.js} +169 -7
- package/dist/chunk-4QFNFERM.js.map +1 -0
- package/dist/cli.cjs +165 -5
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +169 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +5 -1
- package/package.json +12 -11
- package/dist/chunk-CUNWMAA2.js.map +0 -1
package/dist/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts","../cli.ts"],"sourcesContent":["import { access, mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { compileManifestBundle, runGenerator, type GeneratedFile, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport { capabilityGenerator } from \"@fabricorg/gen-capability\";\nimport { docsGenerator } from \"@fabricorg/gen-docs\";\nimport { eventsGenerator } from \"@fabricorg/gen-events\";\nimport { typesGenerator } from \"@fabricorg/gen-types\";\nimport { prismaGenerator } from \"@fabricorg/gen-prisma\";\nimport { graphqlGenerator } from \"@fabricorg/gen-graphql\";\nimport { sduiGenerator } from \"@fabricorg/gen-sdui\";\nimport { conformanceGenerator } from \"@fabricorg/gen-conformance\";\nimport {\n\tassertAssemblyLockfile,\n\tassertAssemblyRuntimeCompatible,\n\ttype AssemblyLockfile,\n\ttype AvailableCapability,\n} from \"@fabricorg/assembly\";\nimport {\n\tassertSduiReleaseIntegrity,\n\ttype SduiRelease,\n} from \"@fabricorg/sdui-release\";\n\nexport const GENERATOR_TARGETS: Record<string, GeneratorTarget> = {\n\ttypes: typesGenerator,\n\tevents: eventsGenerator,\n\tcapability: capabilityGenerator,\n\tdocs: docsGenerator,\n\tprisma: prismaGenerator,\n\tgraphql: graphqlGenerator,\n\tsdui: sduiGenerator,\n\tconformance: conformanceGenerator,\n};\nconst compareCanonicalStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0;\n\nexport interface GenerateOptions { inputPath: string; outputDirectory: string; targets: string[]; check?: boolean; }\nexport interface GenerateResult { changed: string[]; stale: string[]; files: GeneratedFile[]; }\nexport interface InitializeCapabilityOptions { directory: string; namespace: string; }\nexport interface InitializeCapabilityResult { created: string[]; }\nexport interface CheckApplicationOptions { configPath: string; }\nexport interface CheckApplicationResult {\n\tapplication: string;\n\tcapabilities: number;\n\treleases: number;\n\tassemblyDigest: string;\n}\n\nconst usage = [\n\t\"Usage:\",\n\t\" fabric-gen init capability <namespace> [--directory <path>]\",\n\t\" fabric-gen check-application [--config <path>]\",\n\t\" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]\",\n].join(\"\\n\");\n\nexport class FabricGenUsageError extends Error {\n\toverride readonly name = \"FabricGenUsageError\";\n}\n\nexport function fabricGenCliExitCode(error: unknown): number {\n\treturn error instanceof FabricGenUsageError ? 2 : 1;\n}\n\nfunction flagValue(args: readonly string[], flag: string): string | undefined {\n\tconst index = args.indexOf(flag);\n\tif (index < 0) return undefined;\n\tconst value = args[index + 1];\n\tif (!value || value.startsWith(\"--\")) throw new FabricGenUsageError(usage);\n\treturn value;\n}\n\n/** Execute one CLI command and return its single human-readable result line. */\nexport async function runFabricGenCommand(args: readonly string[]): Promise<string> {\n\tif (args[0] === \"init\") {\n\t\tif (args[1] !== \"capability\" || !args[2] || args[2].startsWith(\"--\")) {\n\t\t\tthrow new FabricGenUsageError(usage);\n\t\t}\n\t\tconst namespace = args[2];\n\t\tconst directory = flagValue(args, \"--directory\") ?? namespace;\n\t\tconst result = await initializeCapability({ directory, namespace });\n\t\treturn `Initialized capability \"${namespace}\" with ${result.created.length} files.`;\n\t}\n\tif (args[0] === \"check-application\") {\n\t\tconst configPath = flagValue(args, \"--config\") ?? \"fabric.application.json\";\n\t\tconst result = await checkApplication({ configPath });\n\t\treturn `Checked \"${result.application}\": ${result.capabilities} capabilities, ${result.releases} releases.`;\n\t}\n\tconst inputPath = flagValue(args, \"--input\");\n\tconst outputDirectory = flagValue(args, \"--out\");\n\tif (!inputPath || !outputDirectory) throw new FabricGenUsageError(usage);\n\tconst result = await generateFromManifest({\n\t\tinputPath,\n\t\toutputDirectory,\n\t\ttargets: (flagValue(args, \"--targets\") ?? \"types,events,capability,docs\")\n\t\t\t.split(\",\")\n\t\t\t.filter(Boolean),\n\t\tcheck: args.includes(\"--check\"),\n\t});\n\treturn `${args.includes(\"--check\") ? \"Checked\" : \"Generated\"} ${result.files.length} files.`;\n}\n\ninterface ApplicationCheckConfig {\n\tformatVersion: 1;\n\tassembly: string;\n\truntimeCapabilities: string;\n\treleases: string[];\n}\n\nasync function readJson(file: string): Promise<unknown> {\n\treturn JSON.parse(await readFile(file, \"utf8\"));\n}\n\nfunction assertApplicationCheckConfig(value: unknown): asserts value is ApplicationCheckConfig {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Application check configuration must be a JSON object.\");\n\t}\n\tconst config = value as Record<string, unknown>;\n\tif (config.formatVersion !== 1) throw new Error(\"Application check configuration formatVersion must be 1.\");\n\tif (typeof config.assembly !== \"string\" || !config.assembly) {\n\t\tthrow new Error(\"Application check configuration assembly must be a file path.\");\n\t}\n\tif (typeof config.runtimeCapabilities !== \"string\" || !config.runtimeCapabilities) {\n\t\tthrow new Error(\"Application check configuration runtimeCapabilities must be a file path.\");\n\t}\n\tif (!Array.isArray(config.releases) || !config.releases.every((entry) => typeof entry === \"string\" && entry)) {\n\t\tthrow new Error(\"Application check configuration releases must be an array of file paths.\");\n\t}\n}\n\n/**\n * Verify an application's immutable composition inputs before deployment.\n * Every runtime capability must exactly match the approved lockfile, and every\n * promoted experience release must be intact and bound to that assembly.\n */\nexport async function checkApplication(\n\toptions: CheckApplicationOptions,\n): Promise<CheckApplicationResult> {\n\tconst configValue = await readJson(options.configPath);\n\tassertApplicationCheckConfig(configValue);\n\tconst base = path.dirname(options.configPath);\n\tconst resolve = (file: string): string => path.resolve(base, file);\n\tconst assembly = await readJson(resolve(configValue.assembly)) as AssemblyLockfile;\n\tassertAssemblyLockfile(assembly);\n\tconst runtimeCapabilities = await readJson(\n\t\tresolve(configValue.runtimeCapabilities),\n\t) as AvailableCapability[];\n\tif (!Array.isArray(runtimeCapabilities)) {\n\t\tthrow new Error(\"Runtime capabilities must be a JSON array.\");\n\t}\n\tassertAssemblyRuntimeCompatible(assembly, runtimeCapabilities);\n\tfor (const releasePath of configValue.releases) {\n\t\tconst release = await readJson(resolve(releasePath)) as SduiRelease;\n\t\ttry {\n\t\t\tassertSduiReleaseIntegrity(release);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${releasePath}\" is invalid: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t\tif (release.assemblyDigest !== assembly.assemblyDigest) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${release.document.name}@${release.document.version}\" belongs to assembly \"${release.assemblyDigest}\", not \"${assembly.assemblyDigest}\".`,\n\t\t\t);\n\t\t}\n\t}\n\treturn {\n\t\tapplication: assembly.application,\n\t\tcapabilities: assembly.capabilities.length,\n\t\treleases: configValue.releases.length,\n\t\tassemblyDigest: assembly.assemblyDigest,\n\t};\n}\n\n/**\n * Create the smallest useful capability source tree. The manifest is accepted\n * by the compiler immediately, while leaving domain vocabulary to the adopter.\n */\nexport async function initializeCapability(\n\toptions: InitializeCapabilityOptions,\n): Promise<InitializeCapabilityResult> {\n\tif (!/^[a-z][a-z0-9-]*$/.test(options.namespace)) {\n\t\tthrow new Error(\"Capability namespace must use lowercase letters, numbers, and hyphens.\");\n\t}\n\tconst displayName = options.namespace\n\t\t.split(\"-\")\n\t\t.map((part, index) => index === 0\n\t\t\t? `${part.charAt(0).toUpperCase()}${part.slice(1)}`\n\t\t\t: part)\n\t\t.join(\" \");\n\tconst manifestPath = path.join(options.directory, \"fabric.manifest.json\");\n\tconst readmePath = path.join(options.directory, \"README.md\");\n\tfor (const file of [readmePath, manifestPath]) {\n\t\ttry {\n\t\t\tawait access(file);\n\t\t\tthrow new Error(`Refusing to overwrite existing file \"${file}\".`);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.startsWith(\"Refusing to overwrite\")) throw error;\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t}\n\t}\n\tconst manifest = {\n\t\tmanifestVersion: 2,\n\t\tnamespace: options.namespace,\n\t\tobjectTypes: [],\n\t\tsubjectTypes: [],\n\t\tidPrefixes: [],\n\t\tdependencies: [],\n\t\tpolicies: [],\n\t\teventTypes: [],\n\t\tactions: [],\n\t\tviews: [],\n\t\tstateMachines: [],\n\t\tcapability: {\n\t\t\tdisplayName,\n\t\t\tdescription: `Governed ${displayName.toLowerCase()} capability.`,\n\t\t\tstability: \"experimental\",\n\t\t},\n\t};\n\tconst readme = [\n\t\t`# ${displayName}`,\n\t\t\"\",\n\t\t\"Define domain objects, governed actions, events, and projections in `fabric.manifest.json`.\",\n\t\t\"\",\n\t\t\"```bash\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated --check\",\n\t\t\"```\",\n\t\t\"\",\n\t].join(\"\\n\");\n\tawait mkdir(options.directory, { recursive: true });\n\tconst created: string[] = [];\n\ttry {\n\t\tfor (const [file, content] of [\n\t\t\t[readmePath, readme],\n\t\t\t[manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`],\n\t\t] as const) {\n\t\t\tawait writeFile(file, content, { encoding: \"utf8\", flag: \"wx\" });\n\t\t\tcreated.push(file);\n\t\t}\n\t} catch (error) {\n\t\tawait Promise.all(created.map((file) => rm(file, { force: true })));\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\tthrow new Error(\"Refusing to overwrite a file created during capability initialization.\");\n\t\t}\n\t\tthrow error;\n\t}\n\treturn { created };\n}\n\nexport async function generateFromManifest(options: GenerateOptions): Promise<GenerateResult> {\n\tconst input = JSON.parse(await readFile(options.inputPath, \"utf8\"));\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) throw new Error(\"Manifest input must be a JSON object.\");\n\tconst bundle = \"modules\" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };\n\tconst ir = compileManifestBundle(bundle);\n\tconst files = (await Promise.all(options.targets.map(async (name) => {\n\t\tconst target = GENERATOR_TARGETS[name];\n\t\tif (!target) throw new Error(`Unknown generator target \"${name}\".`);\n\t\treturn (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));\n\t}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));\n\tconst expected = new Set(files.map((file) => file.path));\n\tconst existing = await listFiles(options.outputDirectory);\n\tconst selectedPrefixes = options.targets.map((target) => `${target}/`);\n\tconst stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));\n\tif (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));\n\tconst changed: string[] = [];\n\tfor (const file of files) {\n\t\tconst target = path.join(options.outputDirectory, file.path);\n\t\tlet current: string | undefined;\n\t\ttry { current = await readFile(target, \"utf8\"); } catch { current = undefined; }\n\t\tif (current !== file.content) {\n\t\t\tchanged.push(file.path);\n\t\t\tif (!options.check) { await mkdir(path.dirname(target), { recursive: true }); await writeFile(target, file.content, \"utf8\"); }\n\t\t}\n\t}\n\tif (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(\", \")}`);\n\treturn { changed, stale, files };\n}\n\nasync function listFiles(directory: string, prefix = \"\"): Promise<string[]> {\n\tlet entries;\n\ttry { entries = await readdir(directory, { withFileTypes: true }); } catch { return []; }\n\tconst nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));\n\treturn nested.flat().sort();\n}\n","#!/usr/bin/env node\nimport { fabricGenCliExitCode, runFabricGenCommand } from \"./index\";\n\nconst args = process.argv.slice(2);\nrunFabricGenCommand(args)\n\t.then((message) => console.log(message))\n\t.catch((error: unknown) => {\n\t\tconsole.error(error instanceof Error ? error.message : String(error));\n\t\tprocess.exitCode = fabricGenCliExitCode(error);\n\t});\n"],"mappings":"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","names":["args","result","path"]}
|
|
1
|
+
{"version":3,"sources":["../index.ts","../cli.ts"],"sourcesContent":["import { access, mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport { createPrivateKey } from \"node:crypto\";\nimport path from \"node:path\";\nimport { compileManifestBundle, runGenerator, type GeneratedFile, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport { capabilityGenerator } from \"@fabricorg/gen-capability\";\nimport { docsGenerator } from \"@fabricorg/gen-docs\";\nimport { eventsGenerator } from \"@fabricorg/gen-events\";\nimport { typesGenerator } from \"@fabricorg/gen-types\";\nimport { prismaGenerator } from \"@fabricorg/gen-prisma\";\nimport { graphqlGenerator } from \"@fabricorg/gen-graphql\";\nimport { sduiGenerator } from \"@fabricorg/gen-sdui\";\nimport type { UsageContractDocument } from \"@fabricorg/gen-capability\";\nimport { createEs256ReleaseSigner, promoteExperienceRelease } from \"@fabricorg/sdui-composer\";\nimport { conformanceGenerator } from \"@fabricorg/gen-conformance\";\nimport {\n\tassertAssemblyLockfile,\n\tassertAssemblyRuntimeCompatible,\n\ttype AssemblyLockfile,\n\ttype AvailableCapability,\n} from \"@fabricorg/assembly\";\nimport {\n\tassertSduiReleaseIntegrity,\n\ttype SduiRelease,\n} from \"@fabricorg/sdui-release\";\n\nexport const GENERATOR_TARGETS: Record<string, GeneratorTarget> = {\n\ttypes: typesGenerator,\n\tevents: eventsGenerator,\n\tcapability: capabilityGenerator,\n\tdocs: docsGenerator,\n\tprisma: prismaGenerator,\n\tgraphql: graphqlGenerator,\n\tsdui: sduiGenerator,\n\tconformance: conformanceGenerator,\n};\nconst compareCanonicalStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0;\n\nexport interface GenerateOptions { inputPath: string; outputDirectory: string; targets: string[]; check?: boolean; }\nexport interface GenerateResult { changed: string[]; stale: string[]; files: GeneratedFile[]; }\nexport interface InitializeCapabilityOptions { directory: string; namespace: string; }\nexport interface InitializeCapabilityResult { created: string[]; }\nexport interface InitializeExperienceOptions { directory: string; application: string; }\nexport interface InitializeExperienceResult { created: string[]; }\nexport interface CheckApplicationOptions { configPath: string; }\nexport interface PromoteExperienceOptions {\n\tconfigPath: string;\n\t/** PEM-encoded ES256 private key. Never read from the configuration file. */\n\tprivateKeyPath: string;\n\toutputPath?: string;\n}\nexport interface PromoteExperienceResult {\n\tapplication: string;\n\treleaseDigest: string;\n\tassemblyDigest: string;\n\troutes: { views: number; intents: number };\n\toutputPath: string;\n}\nexport interface CheckApplicationResult {\n\tapplication: string;\n\tcapabilities: number;\n\treleases: number;\n\tassemblyDigest: string;\n}\n\nconst usage = [\n\t\"Usage:\",\n\t\" fabric-gen init capability <namespace> [--directory <path>]\",\n\t\" fabric-gen init experience <application> [--directory <path>]\",\n\t\" fabric-gen check-application [--config <path>]\",\n\t\" fabric-gen promote-experience --config <path> --key <pem> [--out <path>]\",\n\t\" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]\",\n].join(\"\\n\");\n\nexport class FabricGenUsageError extends Error {\n\toverride readonly name = \"FabricGenUsageError\";\n}\n\nexport function fabricGenCliExitCode(error: unknown): number {\n\treturn error instanceof FabricGenUsageError ? 2 : 1;\n}\n\nfunction flagValue(args: readonly string[], flag: string): string | undefined {\n\tconst index = args.indexOf(flag);\n\tif (index < 0) return undefined;\n\tconst value = args[index + 1];\n\tif (!value || value.startsWith(\"--\")) throw new FabricGenUsageError(usage);\n\treturn value;\n}\n\n/** Execute one CLI command and return its single human-readable result line. */\nexport async function runFabricGenCommand(args: readonly string[]): Promise<string> {\n\tif (args[0] === \"init\") {\n\t\tif (!args[2] || args[2].startsWith(\"--\")) {\n\t\t\tthrow new FabricGenUsageError(usage);\n\t\t}\n\t\tconst name = args[2];\n\t\tconst directory = flagValue(args, \"--directory\") ?? name;\n\t\tif (args[1] === \"capability\") {\n\t\t\tconst result = await initializeCapability({ directory, namespace: name });\n\t\t\treturn `Initialized capability \"${name}\" with ${result.created.length} files.`;\n\t\t}\n\t\tif (args[1] === \"experience\") {\n\t\t\tconst result = await initializeExperience({ directory, application: name });\n\t\t\treturn `Initialized experience integration \"${name}\" with ${result.created.length} files.`;\n\t\t}\n\t\tthrow new FabricGenUsageError(usage);\n\t}\n\tif (args[0] === \"promote-experience\") {\n\t\tconst configPath = flagValue(args, \"--config\");\n\t\tconst privateKeyPath = flagValue(args, \"--key\");\n\t\tif (!configPath) throw new FabricGenUsageError(\"promote-experience requires --config.\");\n\t\tif (!privateKeyPath) throw new FabricGenUsageError(\"promote-experience requires --key.\");\n\t\tconst outputPath = flagValue(args, \"--out\");\n\t\tconst result = await promoteExperience({\n\t\t\tconfigPath,\n\t\t\tprivateKeyPath,\n\t\t\t...(outputPath ? { outputPath } : {}),\n\t\t});\n\t\treturn [\n\t\t\t`Promoted ${result.application} release ${result.releaseDigest.slice(0, 12)} against assembly ${result.assemblyDigest.slice(0, 12)}.`,\n\t\t\t`Routes: ${result.routes.views} views, ${result.routes.intents} intents.`,\n\t\t\t`Wrote ${result.outputPath}`,\n\t\t].join(\"\\n\");\n\t}\n\n\tif (args[0] === \"check-application\") {\n\t\tconst configPath = flagValue(args, \"--config\") ?? \"fabric.application.json\";\n\t\tconst result = await checkApplication({ configPath });\n\t\treturn `Checked \"${result.application}\": ${result.capabilities} capabilities, ${result.releases} releases.`;\n\t}\n\tconst inputPath = flagValue(args, \"--input\");\n\tconst outputDirectory = flagValue(args, \"--out\");\n\tif (!inputPath || !outputDirectory) throw new FabricGenUsageError(usage);\n\tconst result = await generateFromManifest({\n\t\tinputPath,\n\t\toutputDirectory,\n\t\ttargets: (flagValue(args, \"--targets\") ?? \"types,events,capability,docs\")\n\t\t\t.split(\",\")\n\t\t\t.filter(Boolean),\n\t\tcheck: args.includes(\"--check\"),\n\t});\n\treturn `${args.includes(\"--check\") ? \"Checked\" : \"Generated\"} ${result.files.length} files.`;\n}\n\n/**\n * Add experience integration files to an existing application. It deliberately\n * does not create package.json, routes, authentication, billing, or navigation:\n * those remain owned by the Supastarter-derived application shell.\n */\nexport async function initializeExperience(\n\toptions: InitializeExperienceOptions,\n): Promise<InitializeExperienceResult> {\n\tif (!/^[a-z][a-z0-9-]*$/.test(options.application)) {\n\t\tthrow new Error(\"Application name must use lowercase letters, numbers, and hyphens.\");\n\t}\n\tconst functionName = options.application\n\t\t.split(\"-\")\n\t\t.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n\t\t.join(\"\");\n\tconst files = [\n\t\t[\n\t\t\tpath.join(options.directory, \"fabric.experience.ts\"),\n\t\t\t[\n\t\t\t\t'import { createExperienceServerRuntime } from \"@fabricorg/experience-runtime/server\";',\n\t\t\t\t'import { createExperienceGateway } from \"@fabricorg/experience-gateway\";',\n\t\t\t\t\"\",\n\t\t\t\t`export const create${functionName}ExperienceRuntime = (`,\n\t\t\t\t\"\\toptions: Parameters<typeof createExperienceServerRuntime>[0],\",\n\t\t\t\t\") => createExperienceServerRuntime(options);\",\n\t\t\t\t\"\",\n\t\t\t\t`export const create${functionName}ExperienceGateway = (`,\n\t\t\t\t\"\\toptions: Parameters<typeof createExperienceGateway>[0],\",\n\t\t\t\t\") => createExperienceGateway(options);\",\n\t\t\t\t\"\",\n\t\t\t].join(\"\\n\"),\n\t\t],\n\t\t[\n\t\t\tpath.join(options.directory, \"fabric.component-pack.ts\"),\n\t\t\t[\n\t\t\t\t'import { defineComponentPack } from \"@fabricorg/component-pack\";',\n\t\t\t\t\"\",\n\t\t\t\t`export const define${functionName}ComponentPack = (artifactDigest: string) =>`,\n\t\t\t\t\"\\tdefineComponentPack({\",\n\t\t\t\t`\\t\\tname: \"${options.application}\",`,\n\t\t\t\t`\\t\\tnamespace: \"${options.application}\",`,\n\t\t\t\t'\\t\\tversion: \"0.1.0\",',\n\t\t\t\t\"\\t\\tartifactDigest,\",\n\t\t\t\t'\\t\\ttokenContract: { name: \"fabric-family\", version: \"1.0.0\" },',\n\t\t\t\t\"\\t\\tcomponents: {\",\n\t\t\t\t'\\t\\t\\tText: { module: \"./components/text.js\", roles: [\"content\"], slots: [] },',\n\t\t\t\t\"\\t\\t},\",\n\t\t\t\t\"\\t});\",\n\t\t\t\t\"\",\n\t\t\t].join(\"\\n\"),\n\t\t],\n\t\t[\n\t\t\tpath.join(options.directory, \"fabric.application.json\"),\n\t\t\t`${JSON.stringify({\n\t\t\t\tformatVersion: 1,\n\t\t\t\tapplication: options.application,\n\t\t\t\tassembly: \"./fabric.assembly.lock.json\",\n\t\t\t\truntimeCapabilities: \"./fabric.runtime.json\",\n\t\t\t\treleases: [],\n\t\t\t}, null, 2)}\\n`,\n\t\t],\n\t] as const;\n\tawait mkdir(options.directory, { recursive: true });\n\tconst created: string[] = [];\n\ttry {\n\t\tfor (const [file, content] of files) {\n\t\t\tawait writeFile(file, content, { encoding: \"utf8\", flag: \"wx\" });\n\t\t\tcreated.push(file);\n\t\t}\n\t} catch (error) {\n\t\tawait Promise.all(created.map((file) => rm(file, { force: true })));\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\tthrow new Error(\"Refusing to overwrite an existing experience integration file.\");\n\t\t}\n\t\tthrow error;\n\t}\n\treturn { created };\n}\n\ninterface ApplicationCheckConfig {\n\tformatVersion: 1;\n\tassembly: string;\n\truntimeCapabilities: string;\n\treleases: string[];\n}\n\nasync function readJson(file: string): Promise<unknown> {\n\treturn JSON.parse(await readFile(file, \"utf8\"));\n}\n\nfunction assertApplicationCheckConfig(value: unknown): asserts value is ApplicationCheckConfig {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Application check configuration must be a JSON object.\");\n\t}\n\tconst config = value as Record<string, unknown>;\n\tif (config.formatVersion !== 1) throw new Error(\"Application check configuration formatVersion must be 1.\");\n\tif (typeof config.assembly !== \"string\" || !config.assembly) {\n\t\tthrow new Error(\"Application check configuration assembly must be a file path.\");\n\t}\n\tif (typeof config.runtimeCapabilities !== \"string\" || !config.runtimeCapabilities) {\n\t\tthrow new Error(\"Application check configuration runtimeCapabilities must be a file path.\");\n\t}\n\tif (!Array.isArray(config.releases) || !config.releases.every((entry) => typeof entry === \"string\" && entry)) {\n\t\tthrow new Error(\"Application check configuration releases must be an array of file paths.\");\n\t}\n}\n\n/**\n * Verify an application's immutable composition inputs before deployment.\n * Every runtime capability must exactly match the approved lockfile, and every\n * promoted experience release must be intact and bound to that assembly.\n */\nexport async function checkApplication(\n\toptions: CheckApplicationOptions,\n): Promise<CheckApplicationResult> {\n\tconst configValue = await readJson(options.configPath);\n\tassertApplicationCheckConfig(configValue);\n\tconst base = path.dirname(options.configPath);\n\tconst resolve = (file: string): string => path.resolve(base, file);\n\tconst assembly = await readJson(resolve(configValue.assembly)) as AssemblyLockfile;\n\tassertAssemblyLockfile(assembly);\n\tconst runtimeCapabilities = await readJson(\n\t\tresolve(configValue.runtimeCapabilities),\n\t) as AvailableCapability[];\n\tif (!Array.isArray(runtimeCapabilities)) {\n\t\tthrow new Error(\"Runtime capabilities must be a JSON array.\");\n\t}\n\tassertAssemblyRuntimeCompatible(assembly, runtimeCapabilities);\n\tfor (const releasePath of configValue.releases) {\n\t\tconst release = await readJson(resolve(releasePath)) as SduiRelease;\n\t\ttry {\n\t\t\tassertSduiReleaseIntegrity(release);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${releasePath}\" is invalid: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t\tif (release.assemblyDigest !== assembly.assemblyDigest) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${release.document.name}@${release.document.version}\" belongs to assembly \"${release.assemblyDigest}\", not \"${assembly.assemblyDigest}\".`,\n\t\t\t);\n\t\t}\n\t}\n\treturn {\n\t\tapplication: assembly.application,\n\t\tcapabilities: assembly.capabilities.length,\n\t\treleases: configValue.releases.length,\n\t\tassemblyDigest: assembly.assemblyDigest,\n\t};\n}\n\n/**\n * Create the smallest useful capability source tree. The manifest is accepted\n * by the compiler immediately, while leaving domain vocabulary to the adopter.\n */\nexport async function initializeCapability(\n\toptions: InitializeCapabilityOptions,\n): Promise<InitializeCapabilityResult> {\n\tif (!/^[a-z][a-z0-9-]*$/.test(options.namespace)) {\n\t\tthrow new Error(\"Capability namespace must use lowercase letters, numbers, and hyphens.\");\n\t}\n\tconst displayName = options.namespace\n\t\t.split(\"-\")\n\t\t.map((part, index) => index === 0\n\t\t\t? `${part.charAt(0).toUpperCase()}${part.slice(1)}`\n\t\t\t: part)\n\t\t.join(\" \");\n\tconst manifestPath = path.join(options.directory, \"fabric.manifest.json\");\n\tconst readmePath = path.join(options.directory, \"README.md\");\n\tfor (const file of [readmePath, manifestPath]) {\n\t\ttry {\n\t\t\tawait access(file);\n\t\t\tthrow new Error(`Refusing to overwrite existing file \"${file}\".`);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.startsWith(\"Refusing to overwrite\")) throw error;\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t}\n\t}\n\tconst manifest = {\n\t\tmanifestVersion: 2,\n\t\tnamespace: options.namespace,\n\t\tobjectTypes: [],\n\t\tsubjectTypes: [],\n\t\tidPrefixes: [],\n\t\tdependencies: [],\n\t\tpolicies: [],\n\t\teventTypes: [],\n\t\tactions: [],\n\t\tviews: [],\n\t\tstateMachines: [],\n\t\tcapability: {\n\t\t\tdisplayName,\n\t\t\tdescription: `Governed ${displayName.toLowerCase()} capability.`,\n\t\t\tstability: \"experimental\",\n\t\t},\n\t};\n\tconst readme = [\n\t\t`# ${displayName}`,\n\t\t\"\",\n\t\t\"Define domain objects, governed actions, events, and projections in `fabric.manifest.json`.\",\n\t\t\"\",\n\t\t\"```bash\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated --check\",\n\t\t\"```\",\n\t\t\"\",\n\t].join(\"\\n\");\n\tawait mkdir(options.directory, { recursive: true });\n\tconst created: string[] = [];\n\ttry {\n\t\tfor (const [file, content] of [\n\t\t\t[readmePath, readme],\n\t\t\t[manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`],\n\t\t] as const) {\n\t\t\tawait writeFile(file, content, { encoding: \"utf8\", flag: \"wx\" });\n\t\t\tcreated.push(file);\n\t\t}\n\t} catch (error) {\n\t\tawait Promise.all(created.map((file) => rm(file, { force: true })));\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\tthrow new Error(\"Refusing to overwrite a file created during capability initialization.\");\n\t\t}\n\t\tthrow error;\n\t}\n\treturn { created };\n}\n\nexport async function generateFromManifest(options: GenerateOptions): Promise<GenerateResult> {\n\tconst input = JSON.parse(await readFile(options.inputPath, \"utf8\"));\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) throw new Error(\"Manifest input must be a JSON object.\");\n\tconst bundle = \"modules\" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };\n\tconst ir = compileManifestBundle(bundle);\n\tconst files = (await Promise.all(options.targets.map(async (name) => {\n\t\tconst target = GENERATOR_TARGETS[name];\n\t\tif (!target) throw new Error(`Unknown generator target \"${name}\".`);\n\t\treturn (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));\n\t}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));\n\tconst expected = new Set(files.map((file) => file.path));\n\tconst existing = await listFiles(options.outputDirectory);\n\tconst selectedPrefixes = options.targets.map((target) => `${target}/`);\n\tconst stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));\n\tif (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));\n\tconst changed: string[] = [];\n\tfor (const file of files) {\n\t\tconst target = path.join(options.outputDirectory, file.path);\n\t\tlet current: string | undefined;\n\t\ttry { current = await readFile(target, \"utf8\"); } catch { current = undefined; }\n\t\tif (current !== file.content) {\n\t\t\tchanged.push(file.path);\n\t\t\tif (!options.check) { await mkdir(path.dirname(target), { recursive: true }); await writeFile(target, file.content, \"utf8\"); }\n\t\t}\n\t}\n\tif (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(\", \")}`);\n\treturn { changed, stale, files };\n}\n\nasync function listFiles(directory: string, prefix = \"\"): Promise<string[]> {\n\tlet entries;\n\ttry { entries = await readdir(directory, { withFileTypes: true }); } catch { return []; }\n\tconst nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));\n\treturn nested.flat().sort();\n}\n\ninterface ExperiencePromotionConfig {\n\tformatVersion: 1;\n\tapplication: string;\n\tissuer: string;\n\tkeyId: string;\n\tassembly: string;\n\trelease: string;\n\tcontracts: string[];\n}\n\nfunction assertExperiencePromotionConfig(value: unknown): asserts value is ExperiencePromotionConfig {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Experience promotion configuration must be a JSON object.\");\n\t}\n\tconst config = value as Record<string, unknown>;\n\tif (config.formatVersion !== 1) throw new Error(\"Experience promotion configuration formatVersion must be 1.\");\n\tfor (const field of [\"application\", \"issuer\", \"keyId\", \"assembly\", \"release\"] as const) {\n\t\tif (typeof config[field] !== \"string\" || !config[field]) {\n\t\t\tthrow new Error(`Experience promotion configuration ${field} must be a non-empty string.`);\n\t\t}\n\t}\n\t// The application name is interpolated into the default output path and\n\t// signed into the release body, so \"../../x\" would escape the configuration\n\t// directory and \"/etc/x\" would ignore it entirely.\n\tif (!/^[a-z][a-z0-9-]*$/.test(config.application as string)) {\n\t\tthrow new Error(\"Experience promotion configuration application must be lowercase letters, numbers, and hyphens.\");\n\t}\n\tif (!Array.isArray(config.contracts) || !config.contracts.every((entry) => typeof entry === \"string\" && entry)) {\n\t\tthrow new Error(\"Experience promotion configuration contracts must be an array of file paths.\");\n\t}\n\t// A signing key in a checked-in configuration file is a key in version\n\t// control. Enumerating two spellings only catches two spellings, so reject\n\t// anything that reads like one, and reject unknown fields so a future\n\t// spelling cannot arrive unnoticed.\n\tconst known = new Set([\"formatVersion\", \"application\", \"issuer\", \"keyId\", \"assembly\", \"release\", \"contracts\"]);\n\tfor (const field of Object.keys(config)) {\n\t\tif (/key|secret|credential|token|pem|password/i.test(field) && field !== \"keyId\") {\n\t\t\tthrow new Error(`Experience promotion configuration must not carry \"${field}\"; pass the signing key with --key.`);\n\t\t}\n\t\tif (!known.has(field)) {\n\t\t\tthrow new Error(`Experience promotion configuration has an unknown field \"${field}\".`);\n\t\t}\n\t}\n}\n\n/**\n * Turn a validated release into a signed one.\n *\n * Promotion is where a granted `capability://` reference becomes a concrete\n * action id and version, so it is also where that mapping has to be bound to\n * the assembly that approved it. The signing key is a command-line argument\n * rather than a configuration field, because a configuration file is the kind\n * of thing that ends up committed.\n */\nexport async function promoteExperience(\n\toptions: PromoteExperienceOptions,\n): Promise<PromoteExperienceResult> {\n\tconst configValue = await readJson(options.configPath);\n\tassertExperiencePromotionConfig(configValue);\n\tconst base = path.dirname(options.configPath);\n\tconst resolve = (file: string): string => path.resolve(base, file);\n\n\tconst assembly = await readJson(resolve(configValue.assembly)) as AssemblyLockfile;\n\tassertAssemblyLockfile(assembly);\n\tconst release = await readJson(resolve(configValue.release)) as SduiRelease;\n\tassertSduiReleaseIntegrity(release);\n\tconst contracts = await Promise.all(\n\t\tconfigValue.contracts.map(async (file) => await readJson(resolve(file)) as UsageContractDocument),\n\t);\n\n\tconst privateKey = createPrivateKey(await readFile(options.privateKeyPath, \"utf8\"));\n\tconst promoted = await promoteExperienceRelease({\n\t\tapplication: configValue.application,\n\t\trelease,\n\t\tcontracts,\n\t\tassembly,\n\t\tissuer: configValue.issuer,\n\t\tsigner: createEs256ReleaseSigner({ keyId: configValue.keyId, privateKey }),\n\t});\n\n\tconst outputPath = options.outputPath\n\t\t? path.resolve(options.outputPath)\n\t\t: resolve(`${configValue.application}.experience-release.jws`);\n\tawait mkdir(path.dirname(outputPath), { recursive: true });\n\tawait writeFile(outputPath, `${promoted.compactJws}\\n`, \"utf8\");\n\n\treturn {\n\t\tapplication: configValue.application,\n\t\treleaseDigest: release.releaseDigest,\n\t\tassemblyDigest: assembly.assemblyDigest,\n\t\troutes: {\n\t\t\tviews: promoted.release.routes.views.length,\n\t\t\tintents: promoted.release.routes.intents.length,\n\t\t},\n\t\toutputPath,\n\t};\n}\n","#!/usr/bin/env node\nimport { fabricGenCliExitCode, runFabricGenCommand } from \"./index\";\n\nconst args = process.argv.slice(2);\nrunFabricGenCommand(args)\n\t.then((message) => console.log(message))\n\t.catch((error: unknown) => {\n\t\tconsole.error(error instanceof Error ? error.message : String(error));\n\t\tprocess.exitCode = fabricGenCliExitCode(error);\n\t});\n"],"mappings":"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","names":["args","result","path"]}
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -36,10 +36,13 @@ __export(index_exports, {
|
|
|
36
36
|
fabricGenCliExitCode: () => fabricGenCliExitCode,
|
|
37
37
|
generateFromManifest: () => generateFromManifest,
|
|
38
38
|
initializeCapability: () => initializeCapability,
|
|
39
|
+
initializeExperience: () => initializeExperience,
|
|
40
|
+
promoteExperience: () => promoteExperience,
|
|
39
41
|
runFabricGenCommand: () => runFabricGenCommand
|
|
40
42
|
});
|
|
41
43
|
module.exports = __toCommonJS(index_exports);
|
|
42
44
|
var import_promises = require("fs/promises");
|
|
45
|
+
var import_node_crypto = require("crypto");
|
|
43
46
|
var import_node_path = __toESM(require("path"), 1);
|
|
44
47
|
var import_compiler = require("@fabricorg/compiler");
|
|
45
48
|
var import_gen_capability = require("@fabricorg/gen-capability");
|
|
@@ -49,6 +52,7 @@ var import_gen_types = require("@fabricorg/gen-types");
|
|
|
49
52
|
var import_gen_prisma = require("@fabricorg/gen-prisma");
|
|
50
53
|
var import_gen_graphql = require("@fabricorg/gen-graphql");
|
|
51
54
|
var import_gen_sdui = require("@fabricorg/gen-sdui");
|
|
55
|
+
var import_sdui_composer = require("@fabricorg/sdui-composer");
|
|
52
56
|
var import_gen_conformance = require("@fabricorg/gen-conformance");
|
|
53
57
|
var import_assembly = require("@fabricorg/assembly");
|
|
54
58
|
var import_sdui_release = require("@fabricorg/sdui-release");
|
|
@@ -66,7 +70,9 @@ var compareCanonicalStrings = (left, right) => left < right ? -1 : left > right
|
|
|
66
70
|
var usage = [
|
|
67
71
|
"Usage:",
|
|
68
72
|
" fabric-gen init capability <namespace> [--directory <path>]",
|
|
73
|
+
" fabric-gen init experience <application> [--directory <path>]",
|
|
69
74
|
" fabric-gen check-application [--config <path>]",
|
|
75
|
+
" fabric-gen promote-experience --config <path> --key <pem> [--out <path>]",
|
|
70
76
|
" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]"
|
|
71
77
|
].join("\n");
|
|
72
78
|
var FabricGenUsageError = class extends Error {
|
|
@@ -84,13 +90,37 @@ function flagValue(args, flag) {
|
|
|
84
90
|
}
|
|
85
91
|
async function runFabricGenCommand(args) {
|
|
86
92
|
if (args[0] === "init") {
|
|
87
|
-
if (
|
|
93
|
+
if (!args[2] || args[2].startsWith("--")) {
|
|
88
94
|
throw new FabricGenUsageError(usage);
|
|
89
95
|
}
|
|
90
|
-
const
|
|
91
|
-
const directory = flagValue(args, "--directory") ??
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
const name = args[2];
|
|
97
|
+
const directory = flagValue(args, "--directory") ?? name;
|
|
98
|
+
if (args[1] === "capability") {
|
|
99
|
+
const result2 = await initializeCapability({ directory, namespace: name });
|
|
100
|
+
return `Initialized capability "${name}" with ${result2.created.length} files.`;
|
|
101
|
+
}
|
|
102
|
+
if (args[1] === "experience") {
|
|
103
|
+
const result2 = await initializeExperience({ directory, application: name });
|
|
104
|
+
return `Initialized experience integration "${name}" with ${result2.created.length} files.`;
|
|
105
|
+
}
|
|
106
|
+
throw new FabricGenUsageError(usage);
|
|
107
|
+
}
|
|
108
|
+
if (args[0] === "promote-experience") {
|
|
109
|
+
const configPath = flagValue(args, "--config");
|
|
110
|
+
const privateKeyPath = flagValue(args, "--key");
|
|
111
|
+
if (!configPath) throw new FabricGenUsageError("promote-experience requires --config.");
|
|
112
|
+
if (!privateKeyPath) throw new FabricGenUsageError("promote-experience requires --key.");
|
|
113
|
+
const outputPath = flagValue(args, "--out");
|
|
114
|
+
const result2 = await promoteExperience({
|
|
115
|
+
configPath,
|
|
116
|
+
privateKeyPath,
|
|
117
|
+
...outputPath ? { outputPath } : {}
|
|
118
|
+
});
|
|
119
|
+
return [
|
|
120
|
+
`Promoted ${result2.application} release ${result2.releaseDigest.slice(0, 12)} against assembly ${result2.assemblyDigest.slice(0, 12)}.`,
|
|
121
|
+
`Routes: ${result2.routes.views} views, ${result2.routes.intents} intents.`,
|
|
122
|
+
`Wrote ${result2.outputPath}`
|
|
123
|
+
].join("\n");
|
|
94
124
|
}
|
|
95
125
|
if (args[0] === "check-application") {
|
|
96
126
|
const configPath = flagValue(args, "--config") ?? "fabric.application.json";
|
|
@@ -108,6 +138,75 @@ async function runFabricGenCommand(args) {
|
|
|
108
138
|
});
|
|
109
139
|
return `${args.includes("--check") ? "Checked" : "Generated"} ${result.files.length} files.`;
|
|
110
140
|
}
|
|
141
|
+
async function initializeExperience(options) {
|
|
142
|
+
if (!/^[a-z][a-z0-9-]*$/.test(options.application)) {
|
|
143
|
+
throw new Error("Application name must use lowercase letters, numbers, and hyphens.");
|
|
144
|
+
}
|
|
145
|
+
const functionName = options.application.split("-").map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`).join("");
|
|
146
|
+
const files = [
|
|
147
|
+
[
|
|
148
|
+
import_node_path.default.join(options.directory, "fabric.experience.ts"),
|
|
149
|
+
[
|
|
150
|
+
'import { createExperienceServerRuntime } from "@fabricorg/experience-runtime/server";',
|
|
151
|
+
'import { createExperienceGateway } from "@fabricorg/experience-gateway";',
|
|
152
|
+
"",
|
|
153
|
+
`export const create${functionName}ExperienceRuntime = (`,
|
|
154
|
+
" options: Parameters<typeof createExperienceServerRuntime>[0],",
|
|
155
|
+
") => createExperienceServerRuntime(options);",
|
|
156
|
+
"",
|
|
157
|
+
`export const create${functionName}ExperienceGateway = (`,
|
|
158
|
+
" options: Parameters<typeof createExperienceGateway>[0],",
|
|
159
|
+
") => createExperienceGateway(options);",
|
|
160
|
+
""
|
|
161
|
+
].join("\n")
|
|
162
|
+
],
|
|
163
|
+
[
|
|
164
|
+
import_node_path.default.join(options.directory, "fabric.component-pack.ts"),
|
|
165
|
+
[
|
|
166
|
+
'import { defineComponentPack } from "@fabricorg/component-pack";',
|
|
167
|
+
"",
|
|
168
|
+
`export const define${functionName}ComponentPack = (artifactDigest: string) =>`,
|
|
169
|
+
" defineComponentPack({",
|
|
170
|
+
` name: "${options.application}",`,
|
|
171
|
+
` namespace: "${options.application}",`,
|
|
172
|
+
' version: "0.1.0",',
|
|
173
|
+
" artifactDigest,",
|
|
174
|
+
' tokenContract: { name: "fabric-family", version: "1.0.0" },',
|
|
175
|
+
" components: {",
|
|
176
|
+
' Text: { module: "./components/text.js", roles: ["content"], slots: [] },',
|
|
177
|
+
" },",
|
|
178
|
+
" });",
|
|
179
|
+
""
|
|
180
|
+
].join("\n")
|
|
181
|
+
],
|
|
182
|
+
[
|
|
183
|
+
import_node_path.default.join(options.directory, "fabric.application.json"),
|
|
184
|
+
`${JSON.stringify({
|
|
185
|
+
formatVersion: 1,
|
|
186
|
+
application: options.application,
|
|
187
|
+
assembly: "./fabric.assembly.lock.json",
|
|
188
|
+
runtimeCapabilities: "./fabric.runtime.json",
|
|
189
|
+
releases: []
|
|
190
|
+
}, null, 2)}
|
|
191
|
+
`
|
|
192
|
+
]
|
|
193
|
+
];
|
|
194
|
+
await (0, import_promises.mkdir)(options.directory, { recursive: true });
|
|
195
|
+
const created = [];
|
|
196
|
+
try {
|
|
197
|
+
for (const [file, content] of files) {
|
|
198
|
+
await (0, import_promises.writeFile)(file, content, { encoding: "utf8", flag: "wx" });
|
|
199
|
+
created.push(file);
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
await Promise.all(created.map((file) => (0, import_promises.rm)(file, { force: true })));
|
|
203
|
+
if (error.code === "EEXIST") {
|
|
204
|
+
throw new Error("Refusing to overwrite an existing experience integration file.");
|
|
205
|
+
}
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
return { created };
|
|
209
|
+
}
|
|
111
210
|
async function readJson(file) {
|
|
112
211
|
return JSON.parse(await (0, import_promises.readFile)(file, "utf8"));
|
|
113
212
|
}
|
|
@@ -273,6 +372,69 @@ async function listFiles(directory, prefix = "") {
|
|
|
273
372
|
const nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(import_node_path.default.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));
|
|
274
373
|
return nested.flat().sort();
|
|
275
374
|
}
|
|
375
|
+
function assertExperiencePromotionConfig(value) {
|
|
376
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
377
|
+
throw new Error("Experience promotion configuration must be a JSON object.");
|
|
378
|
+
}
|
|
379
|
+
const config = value;
|
|
380
|
+
if (config.formatVersion !== 1) throw new Error("Experience promotion configuration formatVersion must be 1.");
|
|
381
|
+
for (const field of ["application", "issuer", "keyId", "assembly", "release"]) {
|
|
382
|
+
if (typeof config[field] !== "string" || !config[field]) {
|
|
383
|
+
throw new Error(`Experience promotion configuration ${field} must be a non-empty string.`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
if (!/^[a-z][a-z0-9-]*$/.test(config.application)) {
|
|
387
|
+
throw new Error("Experience promotion configuration application must be lowercase letters, numbers, and hyphens.");
|
|
388
|
+
}
|
|
389
|
+
if (!Array.isArray(config.contracts) || !config.contracts.every((entry) => typeof entry === "string" && entry)) {
|
|
390
|
+
throw new Error("Experience promotion configuration contracts must be an array of file paths.");
|
|
391
|
+
}
|
|
392
|
+
const known = /* @__PURE__ */ new Set(["formatVersion", "application", "issuer", "keyId", "assembly", "release", "contracts"]);
|
|
393
|
+
for (const field of Object.keys(config)) {
|
|
394
|
+
if (/key|secret|credential|token|pem|password/i.test(field) && field !== "keyId") {
|
|
395
|
+
throw new Error(`Experience promotion configuration must not carry "${field}"; pass the signing key with --key.`);
|
|
396
|
+
}
|
|
397
|
+
if (!known.has(field)) {
|
|
398
|
+
throw new Error(`Experience promotion configuration has an unknown field "${field}".`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
async function promoteExperience(options) {
|
|
403
|
+
const configValue = await readJson(options.configPath);
|
|
404
|
+
assertExperiencePromotionConfig(configValue);
|
|
405
|
+
const base = import_node_path.default.dirname(options.configPath);
|
|
406
|
+
const resolve = (file) => import_node_path.default.resolve(base, file);
|
|
407
|
+
const assembly = await readJson(resolve(configValue.assembly));
|
|
408
|
+
(0, import_assembly.assertAssemblyLockfile)(assembly);
|
|
409
|
+
const release = await readJson(resolve(configValue.release));
|
|
410
|
+
(0, import_sdui_release.assertSduiReleaseIntegrity)(release);
|
|
411
|
+
const contracts = await Promise.all(
|
|
412
|
+
configValue.contracts.map(async (file) => await readJson(resolve(file)))
|
|
413
|
+
);
|
|
414
|
+
const privateKey = (0, import_node_crypto.createPrivateKey)(await (0, import_promises.readFile)(options.privateKeyPath, "utf8"));
|
|
415
|
+
const promoted = await (0, import_sdui_composer.promoteExperienceRelease)({
|
|
416
|
+
application: configValue.application,
|
|
417
|
+
release,
|
|
418
|
+
contracts,
|
|
419
|
+
assembly,
|
|
420
|
+
issuer: configValue.issuer,
|
|
421
|
+
signer: (0, import_sdui_composer.createEs256ReleaseSigner)({ keyId: configValue.keyId, privateKey })
|
|
422
|
+
});
|
|
423
|
+
const outputPath = options.outputPath ? import_node_path.default.resolve(options.outputPath) : resolve(`${configValue.application}.experience-release.jws`);
|
|
424
|
+
await (0, import_promises.mkdir)(import_node_path.default.dirname(outputPath), { recursive: true });
|
|
425
|
+
await (0, import_promises.writeFile)(outputPath, `${promoted.compactJws}
|
|
426
|
+
`, "utf8");
|
|
427
|
+
return {
|
|
428
|
+
application: configValue.application,
|
|
429
|
+
releaseDigest: release.releaseDigest,
|
|
430
|
+
assemblyDigest: assembly.assemblyDigest,
|
|
431
|
+
routes: {
|
|
432
|
+
views: promoted.release.routes.views.length,
|
|
433
|
+
intents: promoted.release.routes.intents.length
|
|
434
|
+
},
|
|
435
|
+
outputPath
|
|
436
|
+
};
|
|
437
|
+
}
|
|
276
438
|
// Annotate the CommonJS export names for ESM import in node:
|
|
277
439
|
0 && (module.exports = {
|
|
278
440
|
FabricGenUsageError,
|
|
@@ -281,6 +443,8 @@ async function listFiles(directory, prefix = "") {
|
|
|
281
443
|
fabricGenCliExitCode,
|
|
282
444
|
generateFromManifest,
|
|
283
445
|
initializeCapability,
|
|
446
|
+
initializeExperience,
|
|
447
|
+
promoteExperience,
|
|
284
448
|
runFabricGenCommand
|
|
285
449
|
});
|
|
286
450
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { access, mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { compileManifestBundle, runGenerator, type GeneratedFile, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport { capabilityGenerator } from \"@fabricorg/gen-capability\";\nimport { docsGenerator } from \"@fabricorg/gen-docs\";\nimport { eventsGenerator } from \"@fabricorg/gen-events\";\nimport { typesGenerator } from \"@fabricorg/gen-types\";\nimport { prismaGenerator } from \"@fabricorg/gen-prisma\";\nimport { graphqlGenerator } from \"@fabricorg/gen-graphql\";\nimport { sduiGenerator } from \"@fabricorg/gen-sdui\";\nimport { conformanceGenerator } from \"@fabricorg/gen-conformance\";\nimport {\n\tassertAssemblyLockfile,\n\tassertAssemblyRuntimeCompatible,\n\ttype AssemblyLockfile,\n\ttype AvailableCapability,\n} from \"@fabricorg/assembly\";\nimport {\n\tassertSduiReleaseIntegrity,\n\ttype SduiRelease,\n} from \"@fabricorg/sdui-release\";\n\nexport const GENERATOR_TARGETS: Record<string, GeneratorTarget> = {\n\ttypes: typesGenerator,\n\tevents: eventsGenerator,\n\tcapability: capabilityGenerator,\n\tdocs: docsGenerator,\n\tprisma: prismaGenerator,\n\tgraphql: graphqlGenerator,\n\tsdui: sduiGenerator,\n\tconformance: conformanceGenerator,\n};\nconst compareCanonicalStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0;\n\nexport interface GenerateOptions { inputPath: string; outputDirectory: string; targets: string[]; check?: boolean; }\nexport interface GenerateResult { changed: string[]; stale: string[]; files: GeneratedFile[]; }\nexport interface InitializeCapabilityOptions { directory: string; namespace: string; }\nexport interface InitializeCapabilityResult { created: string[]; }\nexport interface CheckApplicationOptions { configPath: string; }\nexport interface CheckApplicationResult {\n\tapplication: string;\n\tcapabilities: number;\n\treleases: number;\n\tassemblyDigest: string;\n}\n\nconst usage = [\n\t\"Usage:\",\n\t\" fabric-gen init capability <namespace> [--directory <path>]\",\n\t\" fabric-gen check-application [--config <path>]\",\n\t\" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]\",\n].join(\"\\n\");\n\nexport class FabricGenUsageError extends Error {\n\toverride readonly name = \"FabricGenUsageError\";\n}\n\nexport function fabricGenCliExitCode(error: unknown): number {\n\treturn error instanceof FabricGenUsageError ? 2 : 1;\n}\n\nfunction flagValue(args: readonly string[], flag: string): string | undefined {\n\tconst index = args.indexOf(flag);\n\tif (index < 0) return undefined;\n\tconst value = args[index + 1];\n\tif (!value || value.startsWith(\"--\")) throw new FabricGenUsageError(usage);\n\treturn value;\n}\n\n/** Execute one CLI command and return its single human-readable result line. */\nexport async function runFabricGenCommand(args: readonly string[]): Promise<string> {\n\tif (args[0] === \"init\") {\n\t\tif (args[1] !== \"capability\" || !args[2] || args[2].startsWith(\"--\")) {\n\t\t\tthrow new FabricGenUsageError(usage);\n\t\t}\n\t\tconst namespace = args[2];\n\t\tconst directory = flagValue(args, \"--directory\") ?? namespace;\n\t\tconst result = await initializeCapability({ directory, namespace });\n\t\treturn `Initialized capability \"${namespace}\" with ${result.created.length} files.`;\n\t}\n\tif (args[0] === \"check-application\") {\n\t\tconst configPath = flagValue(args, \"--config\") ?? \"fabric.application.json\";\n\t\tconst result = await checkApplication({ configPath });\n\t\treturn `Checked \"${result.application}\": ${result.capabilities} capabilities, ${result.releases} releases.`;\n\t}\n\tconst inputPath = flagValue(args, \"--input\");\n\tconst outputDirectory = flagValue(args, \"--out\");\n\tif (!inputPath || !outputDirectory) throw new FabricGenUsageError(usage);\n\tconst result = await generateFromManifest({\n\t\tinputPath,\n\t\toutputDirectory,\n\t\ttargets: (flagValue(args, \"--targets\") ?? \"types,events,capability,docs\")\n\t\t\t.split(\",\")\n\t\t\t.filter(Boolean),\n\t\tcheck: args.includes(\"--check\"),\n\t});\n\treturn `${args.includes(\"--check\") ? \"Checked\" : \"Generated\"} ${result.files.length} files.`;\n}\n\ninterface ApplicationCheckConfig {\n\tformatVersion: 1;\n\tassembly: string;\n\truntimeCapabilities: string;\n\treleases: string[];\n}\n\nasync function readJson(file: string): Promise<unknown> {\n\treturn JSON.parse(await readFile(file, \"utf8\"));\n}\n\nfunction assertApplicationCheckConfig(value: unknown): asserts value is ApplicationCheckConfig {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Application check configuration must be a JSON object.\");\n\t}\n\tconst config = value as Record<string, unknown>;\n\tif (config.formatVersion !== 1) throw new Error(\"Application check configuration formatVersion must be 1.\");\n\tif (typeof config.assembly !== \"string\" || !config.assembly) {\n\t\tthrow new Error(\"Application check configuration assembly must be a file path.\");\n\t}\n\tif (typeof config.runtimeCapabilities !== \"string\" || !config.runtimeCapabilities) {\n\t\tthrow new Error(\"Application check configuration runtimeCapabilities must be a file path.\");\n\t}\n\tif (!Array.isArray(config.releases) || !config.releases.every((entry) => typeof entry === \"string\" && entry)) {\n\t\tthrow new Error(\"Application check configuration releases must be an array of file paths.\");\n\t}\n}\n\n/**\n * Verify an application's immutable composition inputs before deployment.\n * Every runtime capability must exactly match the approved lockfile, and every\n * promoted experience release must be intact and bound to that assembly.\n */\nexport async function checkApplication(\n\toptions: CheckApplicationOptions,\n): Promise<CheckApplicationResult> {\n\tconst configValue = await readJson(options.configPath);\n\tassertApplicationCheckConfig(configValue);\n\tconst base = path.dirname(options.configPath);\n\tconst resolve = (file: string): string => path.resolve(base, file);\n\tconst assembly = await readJson(resolve(configValue.assembly)) as AssemblyLockfile;\n\tassertAssemblyLockfile(assembly);\n\tconst runtimeCapabilities = await readJson(\n\t\tresolve(configValue.runtimeCapabilities),\n\t) as AvailableCapability[];\n\tif (!Array.isArray(runtimeCapabilities)) {\n\t\tthrow new Error(\"Runtime capabilities must be a JSON array.\");\n\t}\n\tassertAssemblyRuntimeCompatible(assembly, runtimeCapabilities);\n\tfor (const releasePath of configValue.releases) {\n\t\tconst release = await readJson(resolve(releasePath)) as SduiRelease;\n\t\ttry {\n\t\t\tassertSduiReleaseIntegrity(release);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${releasePath}\" is invalid: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t\tif (release.assemblyDigest !== assembly.assemblyDigest) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${release.document.name}@${release.document.version}\" belongs to assembly \"${release.assemblyDigest}\", not \"${assembly.assemblyDigest}\".`,\n\t\t\t);\n\t\t}\n\t}\n\treturn {\n\t\tapplication: assembly.application,\n\t\tcapabilities: assembly.capabilities.length,\n\t\treleases: configValue.releases.length,\n\t\tassemblyDigest: assembly.assemblyDigest,\n\t};\n}\n\n/**\n * Create the smallest useful capability source tree. The manifest is accepted\n * by the compiler immediately, while leaving domain vocabulary to the adopter.\n */\nexport async function initializeCapability(\n\toptions: InitializeCapabilityOptions,\n): Promise<InitializeCapabilityResult> {\n\tif (!/^[a-z][a-z0-9-]*$/.test(options.namespace)) {\n\t\tthrow new Error(\"Capability namespace must use lowercase letters, numbers, and hyphens.\");\n\t}\n\tconst displayName = options.namespace\n\t\t.split(\"-\")\n\t\t.map((part, index) => index === 0\n\t\t\t? `${part.charAt(0).toUpperCase()}${part.slice(1)}`\n\t\t\t: part)\n\t\t.join(\" \");\n\tconst manifestPath = path.join(options.directory, \"fabric.manifest.json\");\n\tconst readmePath = path.join(options.directory, \"README.md\");\n\tfor (const file of [readmePath, manifestPath]) {\n\t\ttry {\n\t\t\tawait access(file);\n\t\t\tthrow new Error(`Refusing to overwrite existing file \"${file}\".`);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.startsWith(\"Refusing to overwrite\")) throw error;\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t}\n\t}\n\tconst manifest = {\n\t\tmanifestVersion: 2,\n\t\tnamespace: options.namespace,\n\t\tobjectTypes: [],\n\t\tsubjectTypes: [],\n\t\tidPrefixes: [],\n\t\tdependencies: [],\n\t\tpolicies: [],\n\t\teventTypes: [],\n\t\tactions: [],\n\t\tviews: [],\n\t\tstateMachines: [],\n\t\tcapability: {\n\t\t\tdisplayName,\n\t\t\tdescription: `Governed ${displayName.toLowerCase()} capability.`,\n\t\t\tstability: \"experimental\",\n\t\t},\n\t};\n\tconst readme = [\n\t\t`# ${displayName}`,\n\t\t\"\",\n\t\t\"Define domain objects, governed actions, events, and projections in `fabric.manifest.json`.\",\n\t\t\"\",\n\t\t\"```bash\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated --check\",\n\t\t\"```\",\n\t\t\"\",\n\t].join(\"\\n\");\n\tawait mkdir(options.directory, { recursive: true });\n\tconst created: string[] = [];\n\ttry {\n\t\tfor (const [file, content] of [\n\t\t\t[readmePath, readme],\n\t\t\t[manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`],\n\t\t] as const) {\n\t\t\tawait writeFile(file, content, { encoding: \"utf8\", flag: \"wx\" });\n\t\t\tcreated.push(file);\n\t\t}\n\t} catch (error) {\n\t\tawait Promise.all(created.map((file) => rm(file, { force: true })));\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\tthrow new Error(\"Refusing to overwrite a file created during capability initialization.\");\n\t\t}\n\t\tthrow error;\n\t}\n\treturn { created };\n}\n\nexport async function generateFromManifest(options: GenerateOptions): Promise<GenerateResult> {\n\tconst input = JSON.parse(await readFile(options.inputPath, \"utf8\"));\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) throw new Error(\"Manifest input must be a JSON object.\");\n\tconst bundle = \"modules\" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };\n\tconst ir = compileManifestBundle(bundle);\n\tconst files = (await Promise.all(options.targets.map(async (name) => {\n\t\tconst target = GENERATOR_TARGETS[name];\n\t\tif (!target) throw new Error(`Unknown generator target \"${name}\".`);\n\t\treturn (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));\n\t}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));\n\tconst expected = new Set(files.map((file) => file.path));\n\tconst existing = await listFiles(options.outputDirectory);\n\tconst selectedPrefixes = options.targets.map((target) => `${target}/`);\n\tconst stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));\n\tif (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));\n\tconst changed: string[] = [];\n\tfor (const file of files) {\n\t\tconst target = path.join(options.outputDirectory, file.path);\n\t\tlet current: string | undefined;\n\t\ttry { current = await readFile(target, \"utf8\"); } catch { current = undefined; }\n\t\tif (current !== file.content) {\n\t\t\tchanged.push(file.path);\n\t\t\tif (!options.check) { await mkdir(path.dirname(target), { recursive: true }); await writeFile(target, file.content, \"utf8\"); }\n\t\t}\n\t}\n\tif (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(\", \")}`);\n\treturn { changed, stale, files };\n}\n\nasync function listFiles(directory: string, prefix = \"\"): Promise<string[]> {\n\tlet entries;\n\ttry { entries = await readdir(directory, { withFileTypes: true }); } catch { return []; }\n\tconst nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));\n\treturn nested.flat().sort();\n}\n"],"mappings":"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","names":["result","path"]}
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { access, mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport { createPrivateKey } from \"node:crypto\";\nimport path from \"node:path\";\nimport { compileManifestBundle, runGenerator, type GeneratedFile, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport { capabilityGenerator } from \"@fabricorg/gen-capability\";\nimport { docsGenerator } from \"@fabricorg/gen-docs\";\nimport { eventsGenerator } from \"@fabricorg/gen-events\";\nimport { typesGenerator } from \"@fabricorg/gen-types\";\nimport { prismaGenerator } from \"@fabricorg/gen-prisma\";\nimport { graphqlGenerator } from \"@fabricorg/gen-graphql\";\nimport { sduiGenerator } from \"@fabricorg/gen-sdui\";\nimport type { UsageContractDocument } from \"@fabricorg/gen-capability\";\nimport { createEs256ReleaseSigner, promoteExperienceRelease } from \"@fabricorg/sdui-composer\";\nimport { conformanceGenerator } from \"@fabricorg/gen-conformance\";\nimport {\n\tassertAssemblyLockfile,\n\tassertAssemblyRuntimeCompatible,\n\ttype AssemblyLockfile,\n\ttype AvailableCapability,\n} from \"@fabricorg/assembly\";\nimport {\n\tassertSduiReleaseIntegrity,\n\ttype SduiRelease,\n} from \"@fabricorg/sdui-release\";\n\nexport const GENERATOR_TARGETS: Record<string, GeneratorTarget> = {\n\ttypes: typesGenerator,\n\tevents: eventsGenerator,\n\tcapability: capabilityGenerator,\n\tdocs: docsGenerator,\n\tprisma: prismaGenerator,\n\tgraphql: graphqlGenerator,\n\tsdui: sduiGenerator,\n\tconformance: conformanceGenerator,\n};\nconst compareCanonicalStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0;\n\nexport interface GenerateOptions { inputPath: string; outputDirectory: string; targets: string[]; check?: boolean; }\nexport interface GenerateResult { changed: string[]; stale: string[]; files: GeneratedFile[]; }\nexport interface InitializeCapabilityOptions { directory: string; namespace: string; }\nexport interface InitializeCapabilityResult { created: string[]; }\nexport interface InitializeExperienceOptions { directory: string; application: string; }\nexport interface InitializeExperienceResult { created: string[]; }\nexport interface CheckApplicationOptions { configPath: string; }\nexport interface PromoteExperienceOptions {\n\tconfigPath: string;\n\t/** PEM-encoded ES256 private key. Never read from the configuration file. */\n\tprivateKeyPath: string;\n\toutputPath?: string;\n}\nexport interface PromoteExperienceResult {\n\tapplication: string;\n\treleaseDigest: string;\n\tassemblyDigest: string;\n\troutes: { views: number; intents: number };\n\toutputPath: string;\n}\nexport interface CheckApplicationResult {\n\tapplication: string;\n\tcapabilities: number;\n\treleases: number;\n\tassemblyDigest: string;\n}\n\nconst usage = [\n\t\"Usage:\",\n\t\" fabric-gen init capability <namespace> [--directory <path>]\",\n\t\" fabric-gen init experience <application> [--directory <path>]\",\n\t\" fabric-gen check-application [--config <path>]\",\n\t\" fabric-gen promote-experience --config <path> --key <pem> [--out <path>]\",\n\t\" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]\",\n].join(\"\\n\");\n\nexport class FabricGenUsageError extends Error {\n\toverride readonly name = \"FabricGenUsageError\";\n}\n\nexport function fabricGenCliExitCode(error: unknown): number {\n\treturn error instanceof FabricGenUsageError ? 2 : 1;\n}\n\nfunction flagValue(args: readonly string[], flag: string): string | undefined {\n\tconst index = args.indexOf(flag);\n\tif (index < 0) return undefined;\n\tconst value = args[index + 1];\n\tif (!value || value.startsWith(\"--\")) throw new FabricGenUsageError(usage);\n\treturn value;\n}\n\n/** Execute one CLI command and return its single human-readable result line. */\nexport async function runFabricGenCommand(args: readonly string[]): Promise<string> {\n\tif (args[0] === \"init\") {\n\t\tif (!args[2] || args[2].startsWith(\"--\")) {\n\t\t\tthrow new FabricGenUsageError(usage);\n\t\t}\n\t\tconst name = args[2];\n\t\tconst directory = flagValue(args, \"--directory\") ?? name;\n\t\tif (args[1] === \"capability\") {\n\t\t\tconst result = await initializeCapability({ directory, namespace: name });\n\t\t\treturn `Initialized capability \"${name}\" with ${result.created.length} files.`;\n\t\t}\n\t\tif (args[1] === \"experience\") {\n\t\t\tconst result = await initializeExperience({ directory, application: name });\n\t\t\treturn `Initialized experience integration \"${name}\" with ${result.created.length} files.`;\n\t\t}\n\t\tthrow new FabricGenUsageError(usage);\n\t}\n\tif (args[0] === \"promote-experience\") {\n\t\tconst configPath = flagValue(args, \"--config\");\n\t\tconst privateKeyPath = flagValue(args, \"--key\");\n\t\tif (!configPath) throw new FabricGenUsageError(\"promote-experience requires --config.\");\n\t\tif (!privateKeyPath) throw new FabricGenUsageError(\"promote-experience requires --key.\");\n\t\tconst outputPath = flagValue(args, \"--out\");\n\t\tconst result = await promoteExperience({\n\t\t\tconfigPath,\n\t\t\tprivateKeyPath,\n\t\t\t...(outputPath ? { outputPath } : {}),\n\t\t});\n\t\treturn [\n\t\t\t`Promoted ${result.application} release ${result.releaseDigest.slice(0, 12)} against assembly ${result.assemblyDigest.slice(0, 12)}.`,\n\t\t\t`Routes: ${result.routes.views} views, ${result.routes.intents} intents.`,\n\t\t\t`Wrote ${result.outputPath}`,\n\t\t].join(\"\\n\");\n\t}\n\n\tif (args[0] === \"check-application\") {\n\t\tconst configPath = flagValue(args, \"--config\") ?? \"fabric.application.json\";\n\t\tconst result = await checkApplication({ configPath });\n\t\treturn `Checked \"${result.application}\": ${result.capabilities} capabilities, ${result.releases} releases.`;\n\t}\n\tconst inputPath = flagValue(args, \"--input\");\n\tconst outputDirectory = flagValue(args, \"--out\");\n\tif (!inputPath || !outputDirectory) throw new FabricGenUsageError(usage);\n\tconst result = await generateFromManifest({\n\t\tinputPath,\n\t\toutputDirectory,\n\t\ttargets: (flagValue(args, \"--targets\") ?? \"types,events,capability,docs\")\n\t\t\t.split(\",\")\n\t\t\t.filter(Boolean),\n\t\tcheck: args.includes(\"--check\"),\n\t});\n\treturn `${args.includes(\"--check\") ? \"Checked\" : \"Generated\"} ${result.files.length} files.`;\n}\n\n/**\n * Add experience integration files to an existing application. It deliberately\n * does not create package.json, routes, authentication, billing, or navigation:\n * those remain owned by the Supastarter-derived application shell.\n */\nexport async function initializeExperience(\n\toptions: InitializeExperienceOptions,\n): Promise<InitializeExperienceResult> {\n\tif (!/^[a-z][a-z0-9-]*$/.test(options.application)) {\n\t\tthrow new Error(\"Application name must use lowercase letters, numbers, and hyphens.\");\n\t}\n\tconst functionName = options.application\n\t\t.split(\"-\")\n\t\t.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n\t\t.join(\"\");\n\tconst files = [\n\t\t[\n\t\t\tpath.join(options.directory, \"fabric.experience.ts\"),\n\t\t\t[\n\t\t\t\t'import { createExperienceServerRuntime } from \"@fabricorg/experience-runtime/server\";',\n\t\t\t\t'import { createExperienceGateway } from \"@fabricorg/experience-gateway\";',\n\t\t\t\t\"\",\n\t\t\t\t`export const create${functionName}ExperienceRuntime = (`,\n\t\t\t\t\"\\toptions: Parameters<typeof createExperienceServerRuntime>[0],\",\n\t\t\t\t\") => createExperienceServerRuntime(options);\",\n\t\t\t\t\"\",\n\t\t\t\t`export const create${functionName}ExperienceGateway = (`,\n\t\t\t\t\"\\toptions: Parameters<typeof createExperienceGateway>[0],\",\n\t\t\t\t\") => createExperienceGateway(options);\",\n\t\t\t\t\"\",\n\t\t\t].join(\"\\n\"),\n\t\t],\n\t\t[\n\t\t\tpath.join(options.directory, \"fabric.component-pack.ts\"),\n\t\t\t[\n\t\t\t\t'import { defineComponentPack } from \"@fabricorg/component-pack\";',\n\t\t\t\t\"\",\n\t\t\t\t`export const define${functionName}ComponentPack = (artifactDigest: string) =>`,\n\t\t\t\t\"\\tdefineComponentPack({\",\n\t\t\t\t`\\t\\tname: \"${options.application}\",`,\n\t\t\t\t`\\t\\tnamespace: \"${options.application}\",`,\n\t\t\t\t'\\t\\tversion: \"0.1.0\",',\n\t\t\t\t\"\\t\\tartifactDigest,\",\n\t\t\t\t'\\t\\ttokenContract: { name: \"fabric-family\", version: \"1.0.0\" },',\n\t\t\t\t\"\\t\\tcomponents: {\",\n\t\t\t\t'\\t\\t\\tText: { module: \"./components/text.js\", roles: [\"content\"], slots: [] },',\n\t\t\t\t\"\\t\\t},\",\n\t\t\t\t\"\\t});\",\n\t\t\t\t\"\",\n\t\t\t].join(\"\\n\"),\n\t\t],\n\t\t[\n\t\t\tpath.join(options.directory, \"fabric.application.json\"),\n\t\t\t`${JSON.stringify({\n\t\t\t\tformatVersion: 1,\n\t\t\t\tapplication: options.application,\n\t\t\t\tassembly: \"./fabric.assembly.lock.json\",\n\t\t\t\truntimeCapabilities: \"./fabric.runtime.json\",\n\t\t\t\treleases: [],\n\t\t\t}, null, 2)}\\n`,\n\t\t],\n\t] as const;\n\tawait mkdir(options.directory, { recursive: true });\n\tconst created: string[] = [];\n\ttry {\n\t\tfor (const [file, content] of files) {\n\t\t\tawait writeFile(file, content, { encoding: \"utf8\", flag: \"wx\" });\n\t\t\tcreated.push(file);\n\t\t}\n\t} catch (error) {\n\t\tawait Promise.all(created.map((file) => rm(file, { force: true })));\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\tthrow new Error(\"Refusing to overwrite an existing experience integration file.\");\n\t\t}\n\t\tthrow error;\n\t}\n\treturn { created };\n}\n\ninterface ApplicationCheckConfig {\n\tformatVersion: 1;\n\tassembly: string;\n\truntimeCapabilities: string;\n\treleases: string[];\n}\n\nasync function readJson(file: string): Promise<unknown> {\n\treturn JSON.parse(await readFile(file, \"utf8\"));\n}\n\nfunction assertApplicationCheckConfig(value: unknown): asserts value is ApplicationCheckConfig {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Application check configuration must be a JSON object.\");\n\t}\n\tconst config = value as Record<string, unknown>;\n\tif (config.formatVersion !== 1) throw new Error(\"Application check configuration formatVersion must be 1.\");\n\tif (typeof config.assembly !== \"string\" || !config.assembly) {\n\t\tthrow new Error(\"Application check configuration assembly must be a file path.\");\n\t}\n\tif (typeof config.runtimeCapabilities !== \"string\" || !config.runtimeCapabilities) {\n\t\tthrow new Error(\"Application check configuration runtimeCapabilities must be a file path.\");\n\t}\n\tif (!Array.isArray(config.releases) || !config.releases.every((entry) => typeof entry === \"string\" && entry)) {\n\t\tthrow new Error(\"Application check configuration releases must be an array of file paths.\");\n\t}\n}\n\n/**\n * Verify an application's immutable composition inputs before deployment.\n * Every runtime capability must exactly match the approved lockfile, and every\n * promoted experience release must be intact and bound to that assembly.\n */\nexport async function checkApplication(\n\toptions: CheckApplicationOptions,\n): Promise<CheckApplicationResult> {\n\tconst configValue = await readJson(options.configPath);\n\tassertApplicationCheckConfig(configValue);\n\tconst base = path.dirname(options.configPath);\n\tconst resolve = (file: string): string => path.resolve(base, file);\n\tconst assembly = await readJson(resolve(configValue.assembly)) as AssemblyLockfile;\n\tassertAssemblyLockfile(assembly);\n\tconst runtimeCapabilities = await readJson(\n\t\tresolve(configValue.runtimeCapabilities),\n\t) as AvailableCapability[];\n\tif (!Array.isArray(runtimeCapabilities)) {\n\t\tthrow new Error(\"Runtime capabilities must be a JSON array.\");\n\t}\n\tassertAssemblyRuntimeCompatible(assembly, runtimeCapabilities);\n\tfor (const releasePath of configValue.releases) {\n\t\tconst release = await readJson(resolve(releasePath)) as SduiRelease;\n\t\ttry {\n\t\t\tassertSduiReleaseIntegrity(release);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${releasePath}\" is invalid: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t\tif (release.assemblyDigest !== assembly.assemblyDigest) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${release.document.name}@${release.document.version}\" belongs to assembly \"${release.assemblyDigest}\", not \"${assembly.assemblyDigest}\".`,\n\t\t\t);\n\t\t}\n\t}\n\treturn {\n\t\tapplication: assembly.application,\n\t\tcapabilities: assembly.capabilities.length,\n\t\treleases: configValue.releases.length,\n\t\tassemblyDigest: assembly.assemblyDigest,\n\t};\n}\n\n/**\n * Create the smallest useful capability source tree. The manifest is accepted\n * by the compiler immediately, while leaving domain vocabulary to the adopter.\n */\nexport async function initializeCapability(\n\toptions: InitializeCapabilityOptions,\n): Promise<InitializeCapabilityResult> {\n\tif (!/^[a-z][a-z0-9-]*$/.test(options.namespace)) {\n\t\tthrow new Error(\"Capability namespace must use lowercase letters, numbers, and hyphens.\");\n\t}\n\tconst displayName = options.namespace\n\t\t.split(\"-\")\n\t\t.map((part, index) => index === 0\n\t\t\t? `${part.charAt(0).toUpperCase()}${part.slice(1)}`\n\t\t\t: part)\n\t\t.join(\" \");\n\tconst manifestPath = path.join(options.directory, \"fabric.manifest.json\");\n\tconst readmePath = path.join(options.directory, \"README.md\");\n\tfor (const file of [readmePath, manifestPath]) {\n\t\ttry {\n\t\t\tawait access(file);\n\t\t\tthrow new Error(`Refusing to overwrite existing file \"${file}\".`);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.startsWith(\"Refusing to overwrite\")) throw error;\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t}\n\t}\n\tconst manifest = {\n\t\tmanifestVersion: 2,\n\t\tnamespace: options.namespace,\n\t\tobjectTypes: [],\n\t\tsubjectTypes: [],\n\t\tidPrefixes: [],\n\t\tdependencies: [],\n\t\tpolicies: [],\n\t\teventTypes: [],\n\t\tactions: [],\n\t\tviews: [],\n\t\tstateMachines: [],\n\t\tcapability: {\n\t\t\tdisplayName,\n\t\t\tdescription: `Governed ${displayName.toLowerCase()} capability.`,\n\t\t\tstability: \"experimental\",\n\t\t},\n\t};\n\tconst readme = [\n\t\t`# ${displayName}`,\n\t\t\"\",\n\t\t\"Define domain objects, governed actions, events, and projections in `fabric.manifest.json`.\",\n\t\t\"\",\n\t\t\"```bash\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated --check\",\n\t\t\"```\",\n\t\t\"\",\n\t].join(\"\\n\");\n\tawait mkdir(options.directory, { recursive: true });\n\tconst created: string[] = [];\n\ttry {\n\t\tfor (const [file, content] of [\n\t\t\t[readmePath, readme],\n\t\t\t[manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`],\n\t\t] as const) {\n\t\t\tawait writeFile(file, content, { encoding: \"utf8\", flag: \"wx\" });\n\t\t\tcreated.push(file);\n\t\t}\n\t} catch (error) {\n\t\tawait Promise.all(created.map((file) => rm(file, { force: true })));\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\tthrow new Error(\"Refusing to overwrite a file created during capability initialization.\");\n\t\t}\n\t\tthrow error;\n\t}\n\treturn { created };\n}\n\nexport async function generateFromManifest(options: GenerateOptions): Promise<GenerateResult> {\n\tconst input = JSON.parse(await readFile(options.inputPath, \"utf8\"));\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) throw new Error(\"Manifest input must be a JSON object.\");\n\tconst bundle = \"modules\" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };\n\tconst ir = compileManifestBundle(bundle);\n\tconst files = (await Promise.all(options.targets.map(async (name) => {\n\t\tconst target = GENERATOR_TARGETS[name];\n\t\tif (!target) throw new Error(`Unknown generator target \"${name}\".`);\n\t\treturn (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));\n\t}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));\n\tconst expected = new Set(files.map((file) => file.path));\n\tconst existing = await listFiles(options.outputDirectory);\n\tconst selectedPrefixes = options.targets.map((target) => `${target}/`);\n\tconst stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));\n\tif (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));\n\tconst changed: string[] = [];\n\tfor (const file of files) {\n\t\tconst target = path.join(options.outputDirectory, file.path);\n\t\tlet current: string | undefined;\n\t\ttry { current = await readFile(target, \"utf8\"); } catch { current = undefined; }\n\t\tif (current !== file.content) {\n\t\t\tchanged.push(file.path);\n\t\t\tif (!options.check) { await mkdir(path.dirname(target), { recursive: true }); await writeFile(target, file.content, \"utf8\"); }\n\t\t}\n\t}\n\tif (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(\", \")}`);\n\treturn { changed, stale, files };\n}\n\nasync function listFiles(directory: string, prefix = \"\"): Promise<string[]> {\n\tlet entries;\n\ttry { entries = await readdir(directory, { withFileTypes: true }); } catch { return []; }\n\tconst nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));\n\treturn nested.flat().sort();\n}\n\ninterface ExperiencePromotionConfig {\n\tformatVersion: 1;\n\tapplication: string;\n\tissuer: string;\n\tkeyId: string;\n\tassembly: string;\n\trelease: string;\n\tcontracts: string[];\n}\n\nfunction assertExperiencePromotionConfig(value: unknown): asserts value is ExperiencePromotionConfig {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Experience promotion configuration must be a JSON object.\");\n\t}\n\tconst config = value as Record<string, unknown>;\n\tif (config.formatVersion !== 1) throw new Error(\"Experience promotion configuration formatVersion must be 1.\");\n\tfor (const field of [\"application\", \"issuer\", \"keyId\", \"assembly\", \"release\"] as const) {\n\t\tif (typeof config[field] !== \"string\" || !config[field]) {\n\t\t\tthrow new Error(`Experience promotion configuration ${field} must be a non-empty string.`);\n\t\t}\n\t}\n\t// The application name is interpolated into the default output path and\n\t// signed into the release body, so \"../../x\" would escape the configuration\n\t// directory and \"/etc/x\" would ignore it entirely.\n\tif (!/^[a-z][a-z0-9-]*$/.test(config.application as string)) {\n\t\tthrow new Error(\"Experience promotion configuration application must be lowercase letters, numbers, and hyphens.\");\n\t}\n\tif (!Array.isArray(config.contracts) || !config.contracts.every((entry) => typeof entry === \"string\" && entry)) {\n\t\tthrow new Error(\"Experience promotion configuration contracts must be an array of file paths.\");\n\t}\n\t// A signing key in a checked-in configuration file is a key in version\n\t// control. Enumerating two spellings only catches two spellings, so reject\n\t// anything that reads like one, and reject unknown fields so a future\n\t// spelling cannot arrive unnoticed.\n\tconst known = new Set([\"formatVersion\", \"application\", \"issuer\", \"keyId\", \"assembly\", \"release\", \"contracts\"]);\n\tfor (const field of Object.keys(config)) {\n\t\tif (/key|secret|credential|token|pem|password/i.test(field) && field !== \"keyId\") {\n\t\t\tthrow new Error(`Experience promotion configuration must not carry \"${field}\"; pass the signing key with --key.`);\n\t\t}\n\t\tif (!known.has(field)) {\n\t\t\tthrow new Error(`Experience promotion configuration has an unknown field \"${field}\".`);\n\t\t}\n\t}\n}\n\n/**\n * Turn a validated release into a signed one.\n *\n * Promotion is where a granted `capability://` reference becomes a concrete\n * action id and version, so it is also where that mapping has to be bound to\n * the assembly that approved it. The signing key is a command-line argument\n * rather than a configuration field, because a configuration file is the kind\n * of thing that ends up committed.\n */\nexport async function promoteExperience(\n\toptions: PromoteExperienceOptions,\n): Promise<PromoteExperienceResult> {\n\tconst configValue = await readJson(options.configPath);\n\tassertExperiencePromotionConfig(configValue);\n\tconst base = path.dirname(options.configPath);\n\tconst resolve = (file: string): string => path.resolve(base, file);\n\n\tconst assembly = await readJson(resolve(configValue.assembly)) as AssemblyLockfile;\n\tassertAssemblyLockfile(assembly);\n\tconst release = await readJson(resolve(configValue.release)) as SduiRelease;\n\tassertSduiReleaseIntegrity(release);\n\tconst contracts = await Promise.all(\n\t\tconfigValue.contracts.map(async (file) => await readJson(resolve(file)) as UsageContractDocument),\n\t);\n\n\tconst privateKey = createPrivateKey(await readFile(options.privateKeyPath, \"utf8\"));\n\tconst promoted = await promoteExperienceRelease({\n\t\tapplication: configValue.application,\n\t\trelease,\n\t\tcontracts,\n\t\tassembly,\n\t\tissuer: configValue.issuer,\n\t\tsigner: createEs256ReleaseSigner({ keyId: configValue.keyId, privateKey }),\n\t});\n\n\tconst outputPath = options.outputPath\n\t\t? path.resolve(options.outputPath)\n\t\t: resolve(`${configValue.application}.experience-release.jws`);\n\tawait mkdir(path.dirname(outputPath), { recursive: true });\n\tawait writeFile(outputPath, `${promoted.compactJws}\\n`, \"utf8\");\n\n\treturn {\n\t\tapplication: configValue.application,\n\t\treleaseDigest: release.releaseDigest,\n\t\tassemblyDigest: assembly.assemblyDigest,\n\t\troutes: {\n\t\t\tviews: promoted.release.routes.views.length,\n\t\t\tintents: promoted.release.routes.intents.length,\n\t\t},\n\t\toutputPath,\n\t};\n}\n"],"mappings":"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","names":["result","path"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -19,9 +19,32 @@ interface InitializeCapabilityOptions {
|
|
|
19
19
|
interface InitializeCapabilityResult {
|
|
20
20
|
created: string[];
|
|
21
21
|
}
|
|
22
|
+
interface InitializeExperienceOptions {
|
|
23
|
+
directory: string;
|
|
24
|
+
application: string;
|
|
25
|
+
}
|
|
26
|
+
interface InitializeExperienceResult {
|
|
27
|
+
created: string[];
|
|
28
|
+
}
|
|
22
29
|
interface CheckApplicationOptions {
|
|
23
30
|
configPath: string;
|
|
24
31
|
}
|
|
32
|
+
interface PromoteExperienceOptions {
|
|
33
|
+
configPath: string;
|
|
34
|
+
/** PEM-encoded ES256 private key. Never read from the configuration file. */
|
|
35
|
+
privateKeyPath: string;
|
|
36
|
+
outputPath?: string;
|
|
37
|
+
}
|
|
38
|
+
interface PromoteExperienceResult {
|
|
39
|
+
application: string;
|
|
40
|
+
releaseDigest: string;
|
|
41
|
+
assemblyDigest: string;
|
|
42
|
+
routes: {
|
|
43
|
+
views: number;
|
|
44
|
+
intents: number;
|
|
45
|
+
};
|
|
46
|
+
outputPath: string;
|
|
47
|
+
}
|
|
25
48
|
interface CheckApplicationResult {
|
|
26
49
|
application: string;
|
|
27
50
|
capabilities: number;
|
|
@@ -34,6 +57,12 @@ declare class FabricGenUsageError extends Error {
|
|
|
34
57
|
declare function fabricGenCliExitCode(error: unknown): number;
|
|
35
58
|
/** Execute one CLI command and return its single human-readable result line. */
|
|
36
59
|
declare function runFabricGenCommand(args: readonly string[]): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Add experience integration files to an existing application. It deliberately
|
|
62
|
+
* does not create package.json, routes, authentication, billing, or navigation:
|
|
63
|
+
* those remain owned by the Supastarter-derived application shell.
|
|
64
|
+
*/
|
|
65
|
+
declare function initializeExperience(options: InitializeExperienceOptions): Promise<InitializeExperienceResult>;
|
|
37
66
|
/**
|
|
38
67
|
* Verify an application's immutable composition inputs before deployment.
|
|
39
68
|
* Every runtime capability must exactly match the approved lockfile, and every
|
|
@@ -46,5 +75,15 @@ declare function checkApplication(options: CheckApplicationOptions): Promise<Che
|
|
|
46
75
|
*/
|
|
47
76
|
declare function initializeCapability(options: InitializeCapabilityOptions): Promise<InitializeCapabilityResult>;
|
|
48
77
|
declare function generateFromManifest(options: GenerateOptions): Promise<GenerateResult>;
|
|
78
|
+
/**
|
|
79
|
+
* Turn a validated release into a signed one.
|
|
80
|
+
*
|
|
81
|
+
* Promotion is where a granted `capability://` reference becomes a concrete
|
|
82
|
+
* action id and version, so it is also where that mapping has to be bound to
|
|
83
|
+
* the assembly that approved it. The signing key is a command-line argument
|
|
84
|
+
* rather than a configuration field, because a configuration file is the kind
|
|
85
|
+
* of thing that ends up committed.
|
|
86
|
+
*/
|
|
87
|
+
declare function promoteExperience(options: PromoteExperienceOptions): Promise<PromoteExperienceResult>;
|
|
49
88
|
|
|
50
|
-
export { type CheckApplicationOptions, type CheckApplicationResult, FabricGenUsageError, GENERATOR_TARGETS, type GenerateOptions, type GenerateResult, type InitializeCapabilityOptions, type InitializeCapabilityResult, checkApplication, fabricGenCliExitCode, generateFromManifest, initializeCapability, runFabricGenCommand };
|
|
89
|
+
export { type CheckApplicationOptions, type CheckApplicationResult, FabricGenUsageError, GENERATOR_TARGETS, type GenerateOptions, type GenerateResult, type InitializeCapabilityOptions, type InitializeCapabilityResult, type InitializeExperienceOptions, type InitializeExperienceResult, type PromoteExperienceOptions, type PromoteExperienceResult, checkApplication, fabricGenCliExitCode, generateFromManifest, initializeCapability, initializeExperience, promoteExperience, runFabricGenCommand };
|
package/dist/index.d.ts
CHANGED
|
@@ -19,9 +19,32 @@ interface InitializeCapabilityOptions {
|
|
|
19
19
|
interface InitializeCapabilityResult {
|
|
20
20
|
created: string[];
|
|
21
21
|
}
|
|
22
|
+
interface InitializeExperienceOptions {
|
|
23
|
+
directory: string;
|
|
24
|
+
application: string;
|
|
25
|
+
}
|
|
26
|
+
interface InitializeExperienceResult {
|
|
27
|
+
created: string[];
|
|
28
|
+
}
|
|
22
29
|
interface CheckApplicationOptions {
|
|
23
30
|
configPath: string;
|
|
24
31
|
}
|
|
32
|
+
interface PromoteExperienceOptions {
|
|
33
|
+
configPath: string;
|
|
34
|
+
/** PEM-encoded ES256 private key. Never read from the configuration file. */
|
|
35
|
+
privateKeyPath: string;
|
|
36
|
+
outputPath?: string;
|
|
37
|
+
}
|
|
38
|
+
interface PromoteExperienceResult {
|
|
39
|
+
application: string;
|
|
40
|
+
releaseDigest: string;
|
|
41
|
+
assemblyDigest: string;
|
|
42
|
+
routes: {
|
|
43
|
+
views: number;
|
|
44
|
+
intents: number;
|
|
45
|
+
};
|
|
46
|
+
outputPath: string;
|
|
47
|
+
}
|
|
25
48
|
interface CheckApplicationResult {
|
|
26
49
|
application: string;
|
|
27
50
|
capabilities: number;
|
|
@@ -34,6 +57,12 @@ declare class FabricGenUsageError extends Error {
|
|
|
34
57
|
declare function fabricGenCliExitCode(error: unknown): number;
|
|
35
58
|
/** Execute one CLI command and return its single human-readable result line. */
|
|
36
59
|
declare function runFabricGenCommand(args: readonly string[]): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Add experience integration files to an existing application. It deliberately
|
|
62
|
+
* does not create package.json, routes, authentication, billing, or navigation:
|
|
63
|
+
* those remain owned by the Supastarter-derived application shell.
|
|
64
|
+
*/
|
|
65
|
+
declare function initializeExperience(options: InitializeExperienceOptions): Promise<InitializeExperienceResult>;
|
|
37
66
|
/**
|
|
38
67
|
* Verify an application's immutable composition inputs before deployment.
|
|
39
68
|
* Every runtime capability must exactly match the approved lockfile, and every
|
|
@@ -46,5 +75,15 @@ declare function checkApplication(options: CheckApplicationOptions): Promise<Che
|
|
|
46
75
|
*/
|
|
47
76
|
declare function initializeCapability(options: InitializeCapabilityOptions): Promise<InitializeCapabilityResult>;
|
|
48
77
|
declare function generateFromManifest(options: GenerateOptions): Promise<GenerateResult>;
|
|
78
|
+
/**
|
|
79
|
+
* Turn a validated release into a signed one.
|
|
80
|
+
*
|
|
81
|
+
* Promotion is where a granted `capability://` reference becomes a concrete
|
|
82
|
+
* action id and version, so it is also where that mapping has to be bound to
|
|
83
|
+
* the assembly that approved it. The signing key is a command-line argument
|
|
84
|
+
* rather than a configuration field, because a configuration file is the kind
|
|
85
|
+
* of thing that ends up committed.
|
|
86
|
+
*/
|
|
87
|
+
declare function promoteExperience(options: PromoteExperienceOptions): Promise<PromoteExperienceResult>;
|
|
49
88
|
|
|
50
|
-
export { type CheckApplicationOptions, type CheckApplicationResult, FabricGenUsageError, GENERATOR_TARGETS, type GenerateOptions, type GenerateResult, type InitializeCapabilityOptions, type InitializeCapabilityResult, checkApplication, fabricGenCliExitCode, generateFromManifest, initializeCapability, runFabricGenCommand };
|
|
89
|
+
export { type CheckApplicationOptions, type CheckApplicationResult, FabricGenUsageError, GENERATOR_TARGETS, type GenerateOptions, type GenerateResult, type InitializeCapabilityOptions, type InitializeCapabilityResult, type InitializeExperienceOptions, type InitializeExperienceResult, type PromoteExperienceOptions, type PromoteExperienceResult, checkApplication, fabricGenCliExitCode, generateFromManifest, initializeCapability, initializeExperience, promoteExperience, runFabricGenCommand };
|