create-qpq-app 0.1.5 → 0.1.7
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/lib/commonjs/steps/008_transpileToJavaScript.js +108 -5
- package/lib/commonjs/steps/008_transpileToJavaScript.js.map +1 -1
- package/lib/commonjs/steps/013_printNextSteps.js +1 -1
- package/lib/commonjs/steps/013_printNextSteps.js.map +1 -1
- package/lib/esm/steps/008_transpileToJavaScript.js +104 -5
- package/lib/esm/steps/008_transpileToJavaScript.js.map +1 -1
- package/lib/esm/steps/013_printNextSteps.js +1 -1
- package/lib/esm/steps/013_printNextSteps.js.map +1 -1
- package/package.json +6 -4
- package/template/README.md +5 -5
- package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Footer.tsx +3 -2
- package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/InstallChip.tsx +1 -1
- package/template/apps/todo/packages/service-utils/src/defineTodoService.ts +15 -5
- package/template/docusaurus/docs/actions/core/ai/ask-ai-prompt-stream.md +1 -1
- package/template/docusaurus/docs/actions/core/ai/ask-ai-prompt.md +1 -0
- package/template/docusaurus/docs/getting-started.md +93 -754
- package/template/docusaurus/docs/index.md +7 -2
- package/template/package.json +2 -1
- package/template/tsconfig.base.json +4 -0
|
@@ -8,17 +8,120 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.transpileToJavaScript = void 0;
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
18
|
+
const files_1 = require("../lib/files");
|
|
13
19
|
const types_1 = require("../types");
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
20
|
+
// Convert the scaffolded TypeScript app to JavaScript: per-file type
|
|
21
|
+
// stripping (JSX preserved, comments kept), then remove the TypeScript
|
|
22
|
+
// build plumbing the app no longer needs.
|
|
23
|
+
//
|
|
24
|
+
// The qpq toolchain runs the result as-is: the CLI's ts-node require hook
|
|
25
|
+
// compiles the app's ESM-syntax .js at load time (allowJs, added below), and
|
|
26
|
+
// rspack bundles .js/.jsx natively.
|
|
17
27
|
exports.transpileToJavaScript = {
|
|
18
28
|
name: 'Converting to JavaScript',
|
|
19
29
|
shouldRun: (answers) => answers.language === types_1.AppLanguage.javascript,
|
|
20
|
-
run: () => __awaiter(void 0,
|
|
21
|
-
|
|
30
|
+
run: (_a) => __awaiter(void 0, [_a], void 0, function* ({ targetDirectory }) {
|
|
31
|
+
var _b, _c, _d;
|
|
32
|
+
// Lazy so TypeScript scaffolds never load the compiler.
|
|
33
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
34
|
+
const ts = require('typescript');
|
|
35
|
+
const prettier = require('prettier');
|
|
36
|
+
/* eslint-enable @typescript-eslint/no-require-imports */
|
|
37
|
+
// The transpiler re-prints files in its own style; format the output with
|
|
38
|
+
// the app's own prettier settings so generated code matches the repo.
|
|
39
|
+
const prettierRcPath = path_1.default.join(targetDirectory, '.prettierrc');
|
|
40
|
+
const prettierOptions = fs_1.default.existsSync(prettierRcPath) ? (0, files_1.readJsonFile)(prettierRcPath) : {};
|
|
41
|
+
const compilerOptions = {
|
|
42
|
+
target: ts.ScriptTarget.ESNext,
|
|
43
|
+
module: ts.ModuleKind.ESNext, // keep import/export statements as written
|
|
44
|
+
jsx: ts.JsxEmit.Preserve,
|
|
45
|
+
removeComments: false,
|
|
46
|
+
};
|
|
47
|
+
let converted = 0;
|
|
48
|
+
for (const filePath of (0, files_1.listFilesRecursive)(targetDirectory)) {
|
|
49
|
+
if (filePath.endsWith('.d.ts')) {
|
|
50
|
+
fs_1.default.rmSync(filePath);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const isTsx = filePath.endsWith('.tsx');
|
|
54
|
+
if (!isTsx && !filePath.endsWith('.ts')) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const source = fs_1.default.readFileSync(filePath, 'utf8');
|
|
58
|
+
const { outputText } = ts.transpileModule(source, { compilerOptions, fileName: filePath });
|
|
59
|
+
// Type-only statements leave blank gaps behind — collapse runs of them.
|
|
60
|
+
const collapsed = outputText.replace(/\n{3,}/g, '\n\n');
|
|
61
|
+
const outputPath = filePath.replace(/\.tsx?$/, isTsx ? '.jsx' : '.js');
|
|
62
|
+
const output = yield prettier.format(collapsed, Object.assign(Object.assign({}, prettierOptions), { filepath: outputPath }));
|
|
63
|
+
fs_1.default.writeFileSync(outputPath, output);
|
|
64
|
+
fs_1.default.rmSync(filePath);
|
|
65
|
+
converted += 1;
|
|
66
|
+
}
|
|
67
|
+
// TypeScript build plumbing: tsconfigs, the ambient types/ dir, and the
|
|
68
|
+
// per-package tsc scripts all go. Lib packages no longer build — their
|
|
69
|
+
// package.json main points straight at src.
|
|
70
|
+
let libsRepointed = 0;
|
|
71
|
+
for (const filePath of (0, files_1.listFilesRecursive)(targetDirectory)) {
|
|
72
|
+
const baseName = path_1.default.basename(filePath);
|
|
73
|
+
if (baseName.startsWith('tsconfig') && baseName.endsWith('.json') && filePath !== path_1.default.join(targetDirectory, 'tsconfig.json')) {
|
|
74
|
+
fs_1.default.rmSync(filePath);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (baseName === 'package.json' && filePath !== path_1.default.join(targetDirectory, 'package.json')) {
|
|
78
|
+
const packageJson = (0, files_1.readJsonFile)(filePath);
|
|
79
|
+
let changed = false;
|
|
80
|
+
if ((_b = packageJson.scripts) === null || _b === void 0 ? void 0 : _b['validate-ts']) {
|
|
81
|
+
delete packageJson.scripts['validate-ts'];
|
|
82
|
+
changed = true;
|
|
83
|
+
}
|
|
84
|
+
// Lib packages (identified by their tsc build) get served from
|
|
85
|
+
// source. A tsc build with an unexpected main means the template's
|
|
86
|
+
// conventions moved — fail loudly rather than scaffold a broken app.
|
|
87
|
+
if (((_c = packageJson.scripts) === null || _c === void 0 ? void 0 : _c.build) === 'tsc -b') {
|
|
88
|
+
if (packageJson.main !== './dist/src/index.js') {
|
|
89
|
+
throw new Error(`${filePath} has a tsc build but main is "${packageJson.main}" (expected "./dist/src/index.js") — update transpileToJavaScript for the new template convention.`);
|
|
90
|
+
}
|
|
91
|
+
packageJson.main = './src/index.js';
|
|
92
|
+
delete packageJson.typings;
|
|
93
|
+
delete packageJson.scripts.build;
|
|
94
|
+
packageJson.exports = { '.': { default: './src/index.js' } };
|
|
95
|
+
packageJson.files = ['src'];
|
|
96
|
+
changed = true;
|
|
97
|
+
libsRepointed += 1;
|
|
98
|
+
}
|
|
99
|
+
if (changed) {
|
|
100
|
+
(0, files_1.writeJsonFile)(filePath, packageJson);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (converted === 0 || libsRepointed === 0) {
|
|
105
|
+
throw new Error(`JavaScript conversion looks wrong: ${converted} files transpiled, ${libsRepointed} lib packages repointed — has the template changed shape?`);
|
|
106
|
+
}
|
|
107
|
+
// The ROOT tsconfig.json stays — the qpq CLI's ts-node require hook reads
|
|
108
|
+
// its ts-node block, and allowJs makes that hook compile the app's
|
|
109
|
+
// ESM-syntax .js files (imports, __dirname) at load time.
|
|
110
|
+
fs_1.default.rmSync(path_1.default.join(targetDirectory, 'types'), { recursive: true, force: true });
|
|
111
|
+
fs_1.default.rmSync(path_1.default.join(targetDirectory, 'tsconfig.base.json'), { force: true });
|
|
112
|
+
const rootTsconfigPath = path_1.default.join(targetDirectory, 'tsconfig.json');
|
|
113
|
+
const rootTsconfig = (0, files_1.readJsonFile)(rootTsconfigPath);
|
|
114
|
+
rootTsconfig['ts-node'].compilerOptions.allowJs = true;
|
|
115
|
+
// Scope the hook to this repo — allowJs must never recompile quidproquo
|
|
116
|
+
// libs living outside node_modules (file:-linked dev setups).
|
|
117
|
+
rootTsconfig['ts-node'].scope = true;
|
|
118
|
+
rootTsconfig['ts-node'].scopeDir = '.';
|
|
119
|
+
(0, files_1.writeJsonFile)(rootTsconfigPath, rootTsconfig);
|
|
120
|
+
const rootPackageJsonPath = path_1.default.join(targetDirectory, 'package.json');
|
|
121
|
+
const rootPackageJson = (0, files_1.readJsonFile)(rootPackageJsonPath);
|
|
122
|
+
(_d = rootPackageJson.scripts) === null || _d === void 0 ? true : delete _d['validate-ts'];
|
|
123
|
+
(0, files_1.writeJsonFile)(rootPackageJsonPath, rootPackageJson);
|
|
124
|
+
console.log(` Converted ${converted} files to JavaScript.`);
|
|
22
125
|
}),
|
|
23
126
|
};
|
|
24
127
|
//# sourceMappingURL=008_transpileToJavaScript.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"008_transpileToJavaScript.js","sourceRoot":"","sources":["../../../src/steps/008_transpileToJavaScript.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oCAAyD;AAEzD,2EAA2E;AAC3E,0EAA0E;AAC1E,wDAAwD;AAC3C,QAAA,qBAAqB,GAAqB;IACrD,IAAI,EAAE,0BAA0B;IAEhC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,mBAAW,CAAC,UAAU;IAEnE,GAAG,EAAE,GAAS,EAAE;QACd,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;IAC3F,CAAC,CAAA;CACF,CAAC","sourcesContent":["import { AppLanguage, CreateQpqAppStep } from '../types';\n\n// Placeholder for the JavaScript flavour — a later pass will transpile the\n// scaffolded TypeScript sources here. For now it's an honest no-op so the\n// language answer already threads through the pipeline.\nexport const transpileToJavaScript: CreateQpqAppStep = {\n name: 'Converting to JavaScript',\n\n shouldRun: (answers) => answers.language === AppLanguage.javascript,\n\n run: async () => {\n console.log(' JavaScript output is not available yet — generating TypeScript for now.');\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"008_transpileToJavaScript.js","sourceRoot":"","sources":["../../../src/steps/008_transpileToJavaScript.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nimport { listFilesRecursive, readJsonFile, writeJsonFile } from '../lib/files';\nimport { AppLanguage, CreateQpqAppStep } from '../types';\n\n// Convert the scaffolded TypeScript app to JavaScript: per-file type\n// stripping (JSX preserved, comments kept), then remove the TypeScript\n// build plumbing the app no longer needs.\n//\n// The qpq toolchain runs the result as-is: the CLI's ts-node require hook\n// compiles the app's ESM-syntax .js at load time (allowJs, added below), and\n// rspack bundles .js/.jsx natively.\nexport const transpileToJavaScript: CreateQpqAppStep = {\n name: 'Converting to JavaScript',\n\n shouldRun: (answers) => answers.language === AppLanguage.javascript,\n\n run: async ({ targetDirectory }) => {\n // Lazy so TypeScript scaffolds never load the compiler.\n /* eslint-disable @typescript-eslint/no-require-imports */\n const ts = require('typescript') as typeof import('typescript');\n const prettier = require('prettier') as typeof import('prettier');\n /* eslint-enable @typescript-eslint/no-require-imports */\n\n // The transpiler re-prints files in its own style; format the output with\n // the app's own prettier settings so generated code matches the repo.\n const prettierRcPath = path.join(targetDirectory, '.prettierrc');\n const prettierOptions = fs.existsSync(prettierRcPath) ? readJsonFile(prettierRcPath) : {};\n\n const compilerOptions: import('typescript').CompilerOptions = {\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.ESNext, // keep import/export statements as written\n jsx: ts.JsxEmit.Preserve,\n removeComments: false,\n };\n\n let converted = 0;\n for (const filePath of listFilesRecursive(targetDirectory)) {\n if (filePath.endsWith('.d.ts')) {\n fs.rmSync(filePath);\n continue;\n }\n\n const isTsx = filePath.endsWith('.tsx');\n if (!isTsx && !filePath.endsWith('.ts')) {\n continue;\n }\n\n const source = fs.readFileSync(filePath, 'utf8');\n const { outputText } = ts.transpileModule(source, { compilerOptions, fileName: filePath });\n\n // Type-only statements leave blank gaps behind — collapse runs of them.\n const collapsed = outputText.replace(/\\n{3,}/g, '\\n\\n');\n\n const outputPath = filePath.replace(/\\.tsx?$/, isTsx ? '.jsx' : '.js');\n const output = await prettier.format(collapsed, { ...prettierOptions, filepath: outputPath });\n\n fs.writeFileSync(outputPath, output);\n fs.rmSync(filePath);\n converted += 1;\n }\n\n // TypeScript build plumbing: tsconfigs, the ambient types/ dir, and the\n // per-package tsc scripts all go. Lib packages no longer build — their\n // package.json main points straight at src.\n let libsRepointed = 0;\n for (const filePath of listFilesRecursive(targetDirectory)) {\n const baseName = path.basename(filePath);\n\n if (baseName.startsWith('tsconfig') && baseName.endsWith('.json') && filePath !== path.join(targetDirectory, 'tsconfig.json')) {\n fs.rmSync(filePath);\n continue;\n }\n\n if (baseName === 'package.json' && filePath !== path.join(targetDirectory, 'package.json')) {\n const packageJson = readJsonFile(filePath);\n let changed = false;\n\n if (packageJson.scripts?.['validate-ts']) {\n delete packageJson.scripts['validate-ts'];\n changed = true;\n }\n\n // Lib packages (identified by their tsc build) get served from\n // source. A tsc build with an unexpected main means the template's\n // conventions moved — fail loudly rather than scaffold a broken app.\n if (packageJson.scripts?.build === 'tsc -b') {\n if (packageJson.main !== './dist/src/index.js') {\n throw new Error(\n `${filePath} has a tsc build but main is \"${packageJson.main}\" (expected \"./dist/src/index.js\") — update transpileToJavaScript for the new template convention.`,\n );\n }\n\n packageJson.main = './src/index.js';\n delete packageJson.typings;\n delete packageJson.scripts.build;\n packageJson.exports = { '.': { default: './src/index.js' } };\n packageJson.files = ['src'];\n changed = true;\n libsRepointed += 1;\n }\n\n if (changed) {\n writeJsonFile(filePath, packageJson);\n }\n }\n }\n\n if (converted === 0 || libsRepointed === 0) {\n throw new Error(\n `JavaScript conversion looks wrong: ${converted} files transpiled, ${libsRepointed} lib packages repointed — has the template changed shape?`,\n );\n }\n\n // The ROOT tsconfig.json stays — the qpq CLI's ts-node require hook reads\n // its ts-node block, and allowJs makes that hook compile the app's\n // ESM-syntax .js files (imports, __dirname) at load time.\n fs.rmSync(path.join(targetDirectory, 'types'), { recursive: true, force: true });\n fs.rmSync(path.join(targetDirectory, 'tsconfig.base.json'), { force: true });\n\n const rootTsconfigPath = path.join(targetDirectory, 'tsconfig.json');\n const rootTsconfig = readJsonFile(rootTsconfigPath);\n rootTsconfig['ts-node'].compilerOptions.allowJs = true;\n // Scope the hook to this repo — allowJs must never recompile quidproquo\n // libs living outside node_modules (file:-linked dev setups).\n rootTsconfig['ts-node'].scope = true;\n rootTsconfig['ts-node'].scopeDir = '.';\n writeJsonFile(rootTsconfigPath, rootTsconfig);\n\n const rootPackageJsonPath = path.join(targetDirectory, 'package.json');\n const rootPackageJson = readJsonFile(rootPackageJsonPath);\n delete rootPackageJson.scripts?.['validate-ts'];\n writeJsonFile(rootPackageJsonPath, rootPackageJson);\n\n console.log(` Converted ${converted} files to JavaScript.`);\n },\n};\n"]}
|
|
@@ -23,7 +23,7 @@ deploys as a single docker image.
|
|
|
23
23
|
Next steps:
|
|
24
24
|
|
|
25
25
|
cd ${answers.appName}
|
|
26
|
-
${install} npm run go:dev #
|
|
26
|
+
${install} npm run go:dev # api on http://localhost:8080, web on http://localhost:3080
|
|
27
27
|
npm run go # build the docker image (then run the printed docker command)
|
|
28
28
|
|
|
29
29
|
Deploy config lives in apps/${answers.appName}/deploy.config.json (domain: ${answers.domain}).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"013_printNextSteps.js","sourceRoot":"","sources":["../../../src/steps/013_printNextSteps.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEa,QAAA,cAAc,GAAqB;IAC9C,IAAI,EAAE,MAAM;IAEZ,GAAG,EAAE,KAAoB,EAAE,4CAAf,EAAE,OAAO,EAAE;QACrB,MAAM,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kCAAkC,CAAC;QAEtF,OAAO,CAAC,GAAG,CAAC;UACN,OAAO,CAAC,OAAO;;;;;;;OAOlB,OAAO,CAAC,OAAO;EACpB,OAAO;;;8BAGqB,OAAO,CAAC,OAAO,gCAAgC,OAAO,CAAC,MAAM;CAC1F,CAAC,CAAC;IACD,CAAC,CAAA;CACF,CAAC","sourcesContent":["import { CreateQpqAppStep } from '../types';\n\nexport const printNextSteps: CreateQpqAppStep = {\n name: 'Done',\n\n run: async ({ answers }) => {\n const install = answers.installDependencies ? '' : ' npm install\\n npm run build\\n';\n\n console.log(`\nCreated ${answers.appName}!\n\nYour app has five services — admin, auth, design, shell and todo — and\ndeploys as a single docker image.\n\nNext steps:\n\n cd ${answers.appName}\n${install} npm run go:dev #
|
|
1
|
+
{"version":3,"file":"013_printNextSteps.js","sourceRoot":"","sources":["../../../src/steps/013_printNextSteps.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEa,QAAA,cAAc,GAAqB;IAC9C,IAAI,EAAE,MAAM;IAEZ,GAAG,EAAE,KAAoB,EAAE,4CAAf,EAAE,OAAO,EAAE;QACrB,MAAM,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kCAAkC,CAAC;QAEtF,OAAO,CAAC,GAAG,CAAC;UACN,OAAO,CAAC,OAAO;;;;;;;OAOlB,OAAO,CAAC,OAAO;EACpB,OAAO;;;8BAGqB,OAAO,CAAC,OAAO,gCAAgC,OAAO,CAAC,MAAM;CAC1F,CAAC,CAAC;IACD,CAAC,CAAA;CACF,CAAC","sourcesContent":["import { CreateQpqAppStep } from '../types';\n\nexport const printNextSteps: CreateQpqAppStep = {\n name: 'Done',\n\n run: async ({ answers }) => {\n const install = answers.installDependencies ? '' : ' npm install\\n npm run build\\n';\n\n console.log(`\nCreated ${answers.appName}!\n\nYour app has five services — admin, auth, design, shell and todo — and\ndeploys as a single docker image.\n\nNext steps:\n\n cd ${answers.appName}\n${install} npm run go:dev # api on http://localhost:8080, web on http://localhost:3080\n npm run go # build the docker image (then run the printed docker command)\n\nDeploy config lives in apps/${answers.appName}/deploy.config.json (domain: ${answers.domain}).\n`);\n },\n};\n"]}
|
|
@@ -1,12 +1,111 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { listFilesRecursive, readJsonFile, writeJsonFile } from '../lib/files';
|
|
1
4
|
import { AppLanguage } from '../types';
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
+
// Convert the scaffolded TypeScript app to JavaScript: per-file type
|
|
6
|
+
// stripping (JSX preserved, comments kept), then remove the TypeScript
|
|
7
|
+
// build plumbing the app no longer needs.
|
|
8
|
+
//
|
|
9
|
+
// The qpq toolchain runs the result as-is: the CLI's ts-node require hook
|
|
10
|
+
// compiles the app's ESM-syntax .js at load time (allowJs, added below), and
|
|
11
|
+
// rspack bundles .js/.jsx natively.
|
|
5
12
|
export const transpileToJavaScript = {
|
|
6
13
|
name: 'Converting to JavaScript',
|
|
7
14
|
shouldRun: (answers) => answers.language === AppLanguage.javascript,
|
|
8
|
-
run: async () => {
|
|
9
|
-
|
|
15
|
+
run: async ({ targetDirectory }) => {
|
|
16
|
+
// Lazy so TypeScript scaffolds never load the compiler.
|
|
17
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
18
|
+
const ts = require('typescript');
|
|
19
|
+
const prettier = require('prettier');
|
|
20
|
+
/* eslint-enable @typescript-eslint/no-require-imports */
|
|
21
|
+
// The transpiler re-prints files in its own style; format the output with
|
|
22
|
+
// the app's own prettier settings so generated code matches the repo.
|
|
23
|
+
const prettierRcPath = path.join(targetDirectory, '.prettierrc');
|
|
24
|
+
const prettierOptions = fs.existsSync(prettierRcPath) ? readJsonFile(prettierRcPath) : {};
|
|
25
|
+
const compilerOptions = {
|
|
26
|
+
target: ts.ScriptTarget.ESNext,
|
|
27
|
+
module: ts.ModuleKind.ESNext, // keep import/export statements as written
|
|
28
|
+
jsx: ts.JsxEmit.Preserve,
|
|
29
|
+
removeComments: false,
|
|
30
|
+
};
|
|
31
|
+
let converted = 0;
|
|
32
|
+
for (const filePath of listFilesRecursive(targetDirectory)) {
|
|
33
|
+
if (filePath.endsWith('.d.ts')) {
|
|
34
|
+
fs.rmSync(filePath);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const isTsx = filePath.endsWith('.tsx');
|
|
38
|
+
if (!isTsx && !filePath.endsWith('.ts')) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const source = fs.readFileSync(filePath, 'utf8');
|
|
42
|
+
const { outputText } = ts.transpileModule(source, { compilerOptions, fileName: filePath });
|
|
43
|
+
// Type-only statements leave blank gaps behind — collapse runs of them.
|
|
44
|
+
const collapsed = outputText.replace(/\n{3,}/g, '\n\n');
|
|
45
|
+
const outputPath = filePath.replace(/\.tsx?$/, isTsx ? '.jsx' : '.js');
|
|
46
|
+
const output = await prettier.format(collapsed, { ...prettierOptions, filepath: outputPath });
|
|
47
|
+
fs.writeFileSync(outputPath, output);
|
|
48
|
+
fs.rmSync(filePath);
|
|
49
|
+
converted += 1;
|
|
50
|
+
}
|
|
51
|
+
// TypeScript build plumbing: tsconfigs, the ambient types/ dir, and the
|
|
52
|
+
// per-package tsc scripts all go. Lib packages no longer build — their
|
|
53
|
+
// package.json main points straight at src.
|
|
54
|
+
let libsRepointed = 0;
|
|
55
|
+
for (const filePath of listFilesRecursive(targetDirectory)) {
|
|
56
|
+
const baseName = path.basename(filePath);
|
|
57
|
+
if (baseName.startsWith('tsconfig') && baseName.endsWith('.json') && filePath !== path.join(targetDirectory, 'tsconfig.json')) {
|
|
58
|
+
fs.rmSync(filePath);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (baseName === 'package.json' && filePath !== path.join(targetDirectory, 'package.json')) {
|
|
62
|
+
const packageJson = readJsonFile(filePath);
|
|
63
|
+
let changed = false;
|
|
64
|
+
if (packageJson.scripts?.['validate-ts']) {
|
|
65
|
+
delete packageJson.scripts['validate-ts'];
|
|
66
|
+
changed = true;
|
|
67
|
+
}
|
|
68
|
+
// Lib packages (identified by their tsc build) get served from
|
|
69
|
+
// source. A tsc build with an unexpected main means the template's
|
|
70
|
+
// conventions moved — fail loudly rather than scaffold a broken app.
|
|
71
|
+
if (packageJson.scripts?.build === 'tsc -b') {
|
|
72
|
+
if (packageJson.main !== './dist/src/index.js') {
|
|
73
|
+
throw new Error(`${filePath} has a tsc build but main is "${packageJson.main}" (expected "./dist/src/index.js") — update transpileToJavaScript for the new template convention.`);
|
|
74
|
+
}
|
|
75
|
+
packageJson.main = './src/index.js';
|
|
76
|
+
delete packageJson.typings;
|
|
77
|
+
delete packageJson.scripts.build;
|
|
78
|
+
packageJson.exports = { '.': { default: './src/index.js' } };
|
|
79
|
+
packageJson.files = ['src'];
|
|
80
|
+
changed = true;
|
|
81
|
+
libsRepointed += 1;
|
|
82
|
+
}
|
|
83
|
+
if (changed) {
|
|
84
|
+
writeJsonFile(filePath, packageJson);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (converted === 0 || libsRepointed === 0) {
|
|
89
|
+
throw new Error(`JavaScript conversion looks wrong: ${converted} files transpiled, ${libsRepointed} lib packages repointed — has the template changed shape?`);
|
|
90
|
+
}
|
|
91
|
+
// The ROOT tsconfig.json stays — the qpq CLI's ts-node require hook reads
|
|
92
|
+
// its ts-node block, and allowJs makes that hook compile the app's
|
|
93
|
+
// ESM-syntax .js files (imports, __dirname) at load time.
|
|
94
|
+
fs.rmSync(path.join(targetDirectory, 'types'), { recursive: true, force: true });
|
|
95
|
+
fs.rmSync(path.join(targetDirectory, 'tsconfig.base.json'), { force: true });
|
|
96
|
+
const rootTsconfigPath = path.join(targetDirectory, 'tsconfig.json');
|
|
97
|
+
const rootTsconfig = readJsonFile(rootTsconfigPath);
|
|
98
|
+
rootTsconfig['ts-node'].compilerOptions.allowJs = true;
|
|
99
|
+
// Scope the hook to this repo — allowJs must never recompile quidproquo
|
|
100
|
+
// libs living outside node_modules (file:-linked dev setups).
|
|
101
|
+
rootTsconfig['ts-node'].scope = true;
|
|
102
|
+
rootTsconfig['ts-node'].scopeDir = '.';
|
|
103
|
+
writeJsonFile(rootTsconfigPath, rootTsconfig);
|
|
104
|
+
const rootPackageJsonPath = path.join(targetDirectory, 'package.json');
|
|
105
|
+
const rootPackageJson = readJsonFile(rootPackageJsonPath);
|
|
106
|
+
delete rootPackageJson.scripts?.['validate-ts'];
|
|
107
|
+
writeJsonFile(rootPackageJsonPath, rootPackageJson);
|
|
108
|
+
console.log(` Converted ${converted} files to JavaScript.`);
|
|
10
109
|
},
|
|
11
110
|
};
|
|
12
111
|
//# sourceMappingURL=008_transpileToJavaScript.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"008_transpileToJavaScript.js","sourceRoot":"","sources":["../../../src/steps/008_transpileToJavaScript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,UAAU,CAAC;AAEzD,2EAA2E;AAC3E,0EAA0E;AAC1E,wDAAwD;AACxD,MAAM,CAAC,MAAM,qBAAqB,GAAqB;IACrD,IAAI,EAAE,0BAA0B;IAEhC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,WAAW,CAAC,UAAU;IAEnE,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;IAC3F,CAAC;CACF,CAAC","sourcesContent":["import { AppLanguage, CreateQpqAppStep } from '../types';\n\n// Placeholder for the JavaScript flavour — a later pass will transpile the\n// scaffolded TypeScript sources here. For now it's an honest no-op so the\n// language answer already threads through the pipeline.\nexport const transpileToJavaScript: CreateQpqAppStep = {\n name: 'Converting to JavaScript',\n\n shouldRun: (answers) => answers.language === AppLanguage.javascript,\n\n run: async () => {\n console.log(' JavaScript output is not available yet — generating TypeScript for now.');\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"008_transpileToJavaScript.js","sourceRoot":"","sources":["../../../src/steps/008_transpileToJavaScript.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nimport { listFilesRecursive, readJsonFile, writeJsonFile } from '../lib/files';\nimport { AppLanguage, CreateQpqAppStep } from '../types';\n\n// Convert the scaffolded TypeScript app to JavaScript: per-file type\n// stripping (JSX preserved, comments kept), then remove the TypeScript\n// build plumbing the app no longer needs.\n//\n// The qpq toolchain runs the result as-is: the CLI's ts-node require hook\n// compiles the app's ESM-syntax .js at load time (allowJs, added below), and\n// rspack bundles .js/.jsx natively.\nexport const transpileToJavaScript: CreateQpqAppStep = {\n name: 'Converting to JavaScript',\n\n shouldRun: (answers) => answers.language === AppLanguage.javascript,\n\n run: async ({ targetDirectory }) => {\n // Lazy so TypeScript scaffolds never load the compiler.\n /* eslint-disable @typescript-eslint/no-require-imports */\n const ts = require('typescript') as typeof import('typescript');\n const prettier = require('prettier') as typeof import('prettier');\n /* eslint-enable @typescript-eslint/no-require-imports */\n\n // The transpiler re-prints files in its own style; format the output with\n // the app's own prettier settings so generated code matches the repo.\n const prettierRcPath = path.join(targetDirectory, '.prettierrc');\n const prettierOptions = fs.existsSync(prettierRcPath) ? readJsonFile(prettierRcPath) : {};\n\n const compilerOptions: import('typescript').CompilerOptions = {\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.ESNext, // keep import/export statements as written\n jsx: ts.JsxEmit.Preserve,\n removeComments: false,\n };\n\n let converted = 0;\n for (const filePath of listFilesRecursive(targetDirectory)) {\n if (filePath.endsWith('.d.ts')) {\n fs.rmSync(filePath);\n continue;\n }\n\n const isTsx = filePath.endsWith('.tsx');\n if (!isTsx && !filePath.endsWith('.ts')) {\n continue;\n }\n\n const source = fs.readFileSync(filePath, 'utf8');\n const { outputText } = ts.transpileModule(source, { compilerOptions, fileName: filePath });\n\n // Type-only statements leave blank gaps behind — collapse runs of them.\n const collapsed = outputText.replace(/\\n{3,}/g, '\\n\\n');\n\n const outputPath = filePath.replace(/\\.tsx?$/, isTsx ? '.jsx' : '.js');\n const output = await prettier.format(collapsed, { ...prettierOptions, filepath: outputPath });\n\n fs.writeFileSync(outputPath, output);\n fs.rmSync(filePath);\n converted += 1;\n }\n\n // TypeScript build plumbing: tsconfigs, the ambient types/ dir, and the\n // per-package tsc scripts all go. Lib packages no longer build — their\n // package.json main points straight at src.\n let libsRepointed = 0;\n for (const filePath of listFilesRecursive(targetDirectory)) {\n const baseName = path.basename(filePath);\n\n if (baseName.startsWith('tsconfig') && baseName.endsWith('.json') && filePath !== path.join(targetDirectory, 'tsconfig.json')) {\n fs.rmSync(filePath);\n continue;\n }\n\n if (baseName === 'package.json' && filePath !== path.join(targetDirectory, 'package.json')) {\n const packageJson = readJsonFile(filePath);\n let changed = false;\n\n if (packageJson.scripts?.['validate-ts']) {\n delete packageJson.scripts['validate-ts'];\n changed = true;\n }\n\n // Lib packages (identified by their tsc build) get served from\n // source. A tsc build with an unexpected main means the template's\n // conventions moved — fail loudly rather than scaffold a broken app.\n if (packageJson.scripts?.build === 'tsc -b') {\n if (packageJson.main !== './dist/src/index.js') {\n throw new Error(\n `${filePath} has a tsc build but main is \"${packageJson.main}\" (expected \"./dist/src/index.js\") — update transpileToJavaScript for the new template convention.`,\n );\n }\n\n packageJson.main = './src/index.js';\n delete packageJson.typings;\n delete packageJson.scripts.build;\n packageJson.exports = { '.': { default: './src/index.js' } };\n packageJson.files = ['src'];\n changed = true;\n libsRepointed += 1;\n }\n\n if (changed) {\n writeJsonFile(filePath, packageJson);\n }\n }\n }\n\n if (converted === 0 || libsRepointed === 0) {\n throw new Error(\n `JavaScript conversion looks wrong: ${converted} files transpiled, ${libsRepointed} lib packages repointed — has the template changed shape?`,\n );\n }\n\n // The ROOT tsconfig.json stays — the qpq CLI's ts-node require hook reads\n // its ts-node block, and allowJs makes that hook compile the app's\n // ESM-syntax .js files (imports, __dirname) at load time.\n fs.rmSync(path.join(targetDirectory, 'types'), { recursive: true, force: true });\n fs.rmSync(path.join(targetDirectory, 'tsconfig.base.json'), { force: true });\n\n const rootTsconfigPath = path.join(targetDirectory, 'tsconfig.json');\n const rootTsconfig = readJsonFile(rootTsconfigPath);\n rootTsconfig['ts-node'].compilerOptions.allowJs = true;\n // Scope the hook to this repo — allowJs must never recompile quidproquo\n // libs living outside node_modules (file:-linked dev setups).\n rootTsconfig['ts-node'].scope = true;\n rootTsconfig['ts-node'].scopeDir = '.';\n writeJsonFile(rootTsconfigPath, rootTsconfig);\n\n const rootPackageJsonPath = path.join(targetDirectory, 'package.json');\n const rootPackageJson = readJsonFile(rootPackageJsonPath);\n delete rootPackageJson.scripts?.['validate-ts'];\n writeJsonFile(rootPackageJsonPath, rootPackageJson);\n\n console.log(` Converted ${converted} files to JavaScript.`);\n },\n};\n"]}
|
|
@@ -11,7 +11,7 @@ deploys as a single docker image.
|
|
|
11
11
|
Next steps:
|
|
12
12
|
|
|
13
13
|
cd ${answers.appName}
|
|
14
|
-
${install} npm run go:dev #
|
|
14
|
+
${install} npm run go:dev # api on http://localhost:8080, web on http://localhost:3080
|
|
15
15
|
npm run go # build the docker image (then run the printed docker command)
|
|
16
16
|
|
|
17
17
|
Deploy config lives in apps/${answers.appName}/deploy.config.json (domain: ${answers.domain}).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"013_printNextSteps.js","sourceRoot":"","sources":["../../../src/steps/013_printNextSteps.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAqB;IAC9C,IAAI,EAAE,MAAM;IAEZ,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACzB,MAAM,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kCAAkC,CAAC;QAEtF,OAAO,CAAC,GAAG,CAAC;UACN,OAAO,CAAC,OAAO;;;;;;;OAOlB,OAAO,CAAC,OAAO;EACpB,OAAO;;;8BAGqB,OAAO,CAAC,OAAO,gCAAgC,OAAO,CAAC,MAAM;CAC1F,CAAC,CAAC;IACD,CAAC;CACF,CAAC","sourcesContent":["import { CreateQpqAppStep } from '../types';\n\nexport const printNextSteps: CreateQpqAppStep = {\n name: 'Done',\n\n run: async ({ answers }) => {\n const install = answers.installDependencies ? '' : ' npm install\\n npm run build\\n';\n\n console.log(`\nCreated ${answers.appName}!\n\nYour app has five services — admin, auth, design, shell and todo — and\ndeploys as a single docker image.\n\nNext steps:\n\n cd ${answers.appName}\n${install} npm run go:dev #
|
|
1
|
+
{"version":3,"file":"013_printNextSteps.js","sourceRoot":"","sources":["../../../src/steps/013_printNextSteps.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAqB;IAC9C,IAAI,EAAE,MAAM;IAEZ,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACzB,MAAM,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kCAAkC,CAAC;QAEtF,OAAO,CAAC,GAAG,CAAC;UACN,OAAO,CAAC,OAAO;;;;;;;OAOlB,OAAO,CAAC,OAAO;EACpB,OAAO;;;8BAGqB,OAAO,CAAC,OAAO,gCAAgC,OAAO,CAAC,MAAM;CAC1F,CAAC,CAAC;IACD,CAAC;CACF,CAAC","sourcesContent":["import { CreateQpqAppStep } from '../types';\n\nexport const printNextSteps: CreateQpqAppStep = {\n name: 'Done',\n\n run: async ({ answers }) => {\n const install = answers.installDependencies ? '' : ' npm install\\n npm run build\\n';\n\n console.log(`\nCreated ${answers.appName}!\n\nYour app has five services — admin, auth, design, shell and todo — and\ndeploys as a single docker image.\n\nNext steps:\n\n cd ${answers.appName}\n${install} npm run go:dev # api on http://localhost:8080, web on http://localhost:3080\n npm run go # build the docker image (then run the printed docker command)\n\nDeploy config lives in apps/${answers.appName}/deploy.config.json (domain: ${answers.domain}).\n`);\n },\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-qpq-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Scaffold a new quidproquo app — npx create-qpq-app my-app",
|
|
5
5
|
"main": "./lib/commonjs/index.js",
|
|
6
6
|
"module": "./lib/esm/index.js",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"build:esm": "tsc -p tsconfig.esm.json",
|
|
23
23
|
"build:bin-perms": "node -e \"require('fs').chmodSync('lib/commonjs/bin/createQpqApp.js', 0o755)\"",
|
|
24
24
|
"snapshot-template": "node ./scripts/snapshotTemplate.mjs",
|
|
25
|
+
"smoke-test": "node ./scripts/smokeTest.mjs",
|
|
25
26
|
"prepack": "npm run snapshot-template",
|
|
26
27
|
"lint": "npx eslint .",
|
|
27
28
|
"lint:fix": "npx eslint . --fix",
|
|
@@ -44,12 +45,13 @@
|
|
|
44
45
|
},
|
|
45
46
|
"homepage": "https://github.com/joe-coady/quidproquo#readme",
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"@inquirer/prompts": "^8.5.2"
|
|
48
|
+
"@inquirer/prompts": "^8.5.2",
|
|
49
|
+
"prettier": "^3.2.5",
|
|
50
|
+
"typescript": "^5.8.2"
|
|
48
51
|
},
|
|
49
52
|
"devDependencies": {
|
|
50
53
|
"@types/node": "^22.13.13",
|
|
51
|
-
"quidproquo-tsconfig": "0.1.
|
|
52
|
-
"typescript": "^5.8.2"
|
|
54
|
+
"quidproquo-tsconfig": "0.1.7"
|
|
53
55
|
},
|
|
54
56
|
"bin": {
|
|
55
57
|
"create-qpq-app": "./lib/commonjs/bin/createQpqApp.js"
|
package/template/README.md
CHANGED
|
@@ -21,8 +21,7 @@ always runs against the in-repo HEAD. Build the framework first
|
|
|
21
21
|
nvm use # ALWAYS FIRST — switches to the Node version in .nvmrc
|
|
22
22
|
npm install # installs deps + symlinks the sibling quidproquo-* packages (file: refs)
|
|
23
23
|
npm run build # build every workspace (libs -> tsc -b to dist; services -> type-check)
|
|
24
|
-
npm run go:dev #
|
|
25
|
-
npm run go:dev:web # views dev servers (host + one Rspack server per remote)
|
|
24
|
+
npm run go:dev # full local dev stack: api dev server (:8080) + all views dev servers
|
|
26
25
|
```
|
|
27
26
|
|
|
28
27
|
Smoke test once `go:dev` is up:
|
|
@@ -74,7 +73,7 @@ generic CDK app in `quidproquo-deploy-awscdk`.
|
|
|
74
73
|
`defineDevServerOptions({ port })` in its `infrastructure.ts`). The
|
|
75
74
|
only generated artifact is `apps/<app>/tsconfig.federated.json` — regenerate
|
|
76
75
|
with `npm run prep` after adding or removing a marker.
|
|
77
|
-
- **The dev server** (`qpq go:dev`, powered by `quidproquo-dev-server`) loads each service's
|
|
76
|
+
- **The dev server** (`qpq go:dev:api`, powered by `quidproquo-dev-server`) loads each service's
|
|
78
77
|
`infrastructure.ts` directly — no synth needed, just built libs. Its bundle
|
|
79
78
|
externalizes `node_modules` (an externals function in its rspack config) so native modules like
|
|
80
79
|
`sqlite3` load at runtime from their install location.
|
|
@@ -90,7 +89,8 @@ generic CDK app in `quidproquo-deploy-awscdk`.
|
|
|
90
89
|
npm run build # build only the libs (services/views are bundled, not built); scope with --workspace=@qpqjs/constants
|
|
91
90
|
npm run validate-ts # TS check: build libs, then tsc-typecheck every service + views
|
|
92
91
|
npm run prep # regenerate tsconfig.federated.json from // federated.export markers
|
|
93
|
-
npm run go:dev #
|
|
92
|
+
npm run go:dev # api + web dev servers in one process (one ctrl+c stops the lot)
|
|
93
|
+
npm run go:dev:api # backend dev server only, on :8080, every service at /api/<svc>
|
|
94
94
|
npm run go:dev:web # boot ALL views Rspack dev servers (host shell :3080 + remotes on their
|
|
95
95
|
# ports); remotes resolve dynamically at runtime via mf-manifest.json.
|
|
96
96
|
# Subset: npm run go:dev:web -- --only host,shell,design
|
|
@@ -99,7 +99,7 @@ npm run go:dev:web # boot ALL views Rspack dev servers (host shell :3080 + rem
|
|
|
99
99
|
### App selection (multi-app)
|
|
100
100
|
|
|
101
101
|
Every app-facing script (`prep`, `synth`, `go`, `go:docker`, `go:dev`,
|
|
102
|
-
`go:dev:web`) resolves its target app the same way:
|
|
102
|
+
`go:dev:api`, `go:dev:web`) resolves its target app the same way:
|
|
103
103
|
|
|
104
104
|
1. `--app <name>` — **must come after `--`**: `npm run go:dev -- --app qpqjs`
|
|
105
105
|
(this npm silently swallows flags before `--`)
|
package/template/apps/qpqjs/services/design/views/src/components/LandingPage/components/Footer.tsx
CHANGED
|
@@ -18,8 +18,9 @@ export function Footer() {
|
|
|
18
18
|
<span className="hero__title-glow">your first story?</span>
|
|
19
19
|
</h2>
|
|
20
20
|
<p className="footer__cta-sub">
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
One command scaffolds a full app — five services, a local dev
|
|
22
|
+
server, a one-image docker deploy. Yield an action; the runtime
|
|
23
|
+
handles the rest.
|
|
23
24
|
</p>
|
|
24
25
|
<div className="footer__cta-actions">
|
|
25
26
|
<InstallChip />
|
|
@@ -30,6 +30,20 @@ import {
|
|
|
30
30
|
|
|
31
31
|
const modulePrefix = 'todo';
|
|
32
32
|
|
|
33
|
+
// The deployed version tag — git sha when available, so a fresh checkout
|
|
34
|
+
// (or a scaffold that skipped git init) still loads.
|
|
35
|
+
const getVersionTag = (): string => {
|
|
36
|
+
try {
|
|
37
|
+
return execSync('git rev-parse --short HEAD', {
|
|
38
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
39
|
+
})
|
|
40
|
+
.toString()
|
|
41
|
+
.trim();
|
|
42
|
+
} catch {
|
|
43
|
+
return 'no-git';
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
33
47
|
// The shared config every todo service starts from — app identity, dns,
|
|
34
48
|
// auth, admin, api and caching. Each service's infrastructure.ts layers its
|
|
35
49
|
// own resources on top of this.
|
|
@@ -50,11 +64,7 @@ export const defineTodoService = (
|
|
|
50
64
|
process.env.ACTOR_NAME
|
|
51
65
|
),
|
|
52
66
|
|
|
53
|
-
defineApplicationVersion(
|
|
54
|
-
`${execSync('git rev-parse --short HEAD')
|
|
55
|
-
.toString()
|
|
56
|
-
.trim()}-${new Date().toISOString()}`
|
|
57
|
-
),
|
|
67
|
+
defineApplicationVersion(`${getVersionTag()}-${new Date().toISOString()}`),
|
|
58
68
|
|
|
59
69
|
defineDns(domainName),
|
|
60
70
|
|
|
@@ -42,7 +42,7 @@ The parameters are identical to [askAiPrompt](./ask-ai-prompt.md) — see there
|
|
|
42
42
|
| --- | --- | --- |
|
|
43
43
|
| `model` | `AiModel` | Which model to prompt. |
|
|
44
44
|
| `prompt` | `string` | The user prompt. Ignored when `options.messages` is set. |
|
|
45
|
-
| `options` | `AskAiPromptStreamOptions` | `{ system?, aiName?, messages?, reasoning? }` — same shape and meaning as [`AskAiPromptOptions`](./ask-ai-prompt.md#askaipromptoptions). |
|
|
45
|
+
| `options` | `AskAiPromptStreamOptions` | `{ system?, aiName?, messages?, reasoning?, caching? }` — same shape and meaning as [`AskAiPromptOptions`](./ask-ai-prompt.md#askaipromptoptions). |
|
|
46
46
|
|
|
47
47
|
## Returns
|
|
48
48
|
|
|
@@ -49,6 +49,7 @@ function* askAiPrompt(
|
|
|
49
49
|
| `aiName` | `string` | – | Name of a [defineAi](../../../config/core/ai.md) config to bind. This is what wires up tool definitions (and their executors) for the model to call. Omit for a plain, tool-less prompt. |
|
|
50
50
|
| `messages` | [`AiMessage[]`](#aimessage) | – | A full conversation history. When present, this is sent instead of `prompt`, letting you carry a multi-turn dialogue (including prior assistant turns and tool results). |
|
|
51
51
|
| `reasoning` | [`AiReasoningConfig`](#aireasoningconfig) | – | Enables extended thinking. Its presence turns reasoning on; `budgetTokens` caps how many tokens the model may spend thinking before it answers (defaults to `4096` on AWS). |
|
|
52
|
+
| `caching` | `boolean` | – | Marks the system prompt and the last message (or the last `messages` entry) with a Bedrock cache point, so a following call in the same conversation can read everything up to there from cache instead of reprocessing it. |
|
|
52
53
|
|
|
53
54
|
### `AiModel`
|
|
54
55
|
|