@aligent/nx-appbuilder 0.2.0

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.
Files changed (82) hide show
  1. package/README.md +203 -0
  2. package/generators.json +18 -0
  3. package/package.json +20 -0
  4. package/src/generators/app/files/base/.editorconfig.template +18 -0
  5. package/src/generators/app/files/base/.gitignore.template +9 -0
  6. package/src/generators/app/files/base/.nvmrc.template +1 -0
  7. package/src/generators/app/files/base/README.md.template +44 -0
  8. package/src/generators/app/files/base/app.config.yaml.template +77 -0
  9. package/src/generators/app/files/base/babel.actions.config.js.template +6 -0
  10. package/src/generators/app/files/base/eslint.config.mjs.template +8 -0
  11. package/src/generators/app/files/base/global-types/@adobe/ADOBE_TYPES.md.template +10 -0
  12. package/src/generators/app/files/base/global-types/@adobe/aio-sdk/aio-core-logging.d.ts.template +15 -0
  13. package/src/generators/app/files/base/global-types/@adobe/aio-sdk/aio-lib-core-config.d.ts.template +43 -0
  14. package/src/generators/app/files/base/hooks/check-action-types.sh.template +13 -0
  15. package/src/generators/app/files/base/prettier.config.mjs.template +3 -0
  16. package/src/generators/app/files/base/src/actions/tsconfig.json.template +8 -0
  17. package/src/generators/app/files/base/tests/tsconfig.json.template +13 -0
  18. package/src/generators/app/files/base/tsconfig.base.json.template +14 -0
  19. package/src/generators/app/files/base/tsconfig.json.template +3 -0
  20. package/src/generators/app/files/base/vitest.config.ts.template +19 -0
  21. package/src/generators/app/files/commerce-backend-ui/extension-manifest.json.template +8 -0
  22. package/src/generators/app/files/commerce-backend-ui/hooks/check-web-types.sh.template +11 -0
  23. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/actions/registration/index.ts.template +32 -0
  24. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/actions/tsconfig.json.template +8 -0
  25. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/actions/utils/http.ts.template +18 -0
  26. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/actions/utils/runtime.ts.template +47 -0
  27. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/actions/utils/utils.ts.template +187 -0
  28. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/ext.config.yaml.template +20 -0
  29. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/.gitignore.template +2 -0
  30. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/index.html.template +15 -0
  31. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/components/App.tsx.template +37 -0
  32. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/components/ExtensionRegistration.tsx.template +15 -0
  33. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/config.json.d.ts.template +4 -0
  34. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/constants/extension.ts.template +1 -0
  35. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/context/AdobeRuntimeContextProvider.tsx.template +65 -0
  36. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/context/PageContextProvider.tsx.template +78 -0
  37. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/hooks/useAppBuilderAction.ts.template +41 -0
  38. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/hooks/useLazyAppBuilderAction.ts.template +116 -0
  39. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/index.css.template +4 -0
  40. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/index.tsx.template +20 -0
  41. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/src/types/ActionName.ts.template +9 -0
  42. package/src/generators/app/files/commerce-backend-ui/src/commerce-backend-ui-1/web-src/tsconfig.json.template +14 -0
  43. package/src/generators/app/files/commerce-config/src/commerce-configuration-1/ext.config.yaml.template +37 -0
  44. package/src/generators/app/files/commerce-config/src/commerce-configuration-1/my-webpack-config.cjs.template +24 -0
  45. package/src/generators/app/files/commerce-extensibility/app.commerce.config.ts.template +138 -0
  46. package/src/generators/app/files/commerce-extensibility/install.yaml.template +17 -0
  47. package/src/generators/app/files/commerce-extensibility/src/commerce-extensibility-1/ext.config.yaml.template +25 -0
  48. package/src/generators/app/files/commerce-extensibility/src/commerce-extensibility-1/my-webpack-config.cjs.template +24 -0
  49. package/src/generators/app/files/events/global-types/@adobe/aio-sdk/aio-lib-events.d.ts.template +7 -0
  50. package/src/generators/app/files/events/src/actions/handle-sample-event.ts.template +35 -0
  51. package/src/generators/app/files/install-steps/scripts/install/sample-step.js.template +14 -0
  52. package/src/generators/app/files/rest-actions/src/actions/rest-sample.ts.template +30 -0
  53. package/src/generators/app/files/scheduled/src/actions/cron-sample.ts.template +23 -0
  54. package/src/generators/app/generator.d.ts +3 -0
  55. package/src/generators/app/generator.js +38 -0
  56. package/src/generators/app/lib/apply-feature-files.d.ts +9 -0
  57. package/src/generators/app/lib/apply-feature-files.js +76 -0
  58. package/src/generators/app/lib/compose-package-json.d.ts +3 -0
  59. package/src/generators/app/lib/compose-package-json.js +164 -0
  60. package/src/generators/app/lib/normalize-options.d.ts +3 -0
  61. package/src/generators/app/lib/normalize-options.js +67 -0
  62. package/src/generators/app/lib/template-package/package.json +31 -0
  63. package/src/generators/app/lib/update-root-package.d.ts +6 -0
  64. package/src/generators/app/lib/update-root-package.js +23 -0
  65. package/src/generators/app/lib/update-root-tsconfig.d.ts +8 -0
  66. package/src/generators/app/lib/update-root-tsconfig.js +24 -0
  67. package/src/generators/app/schema.d.ts +32 -0
  68. package/src/generators/app/schema.json +73 -0
  69. package/src/generators/preset/files/.gitignore.template +30 -0
  70. package/src/generators/preset/files/.npmrc.template +2 -0
  71. package/src/generators/preset/files/.nvmrc.template +1 -0
  72. package/src/generators/preset/files/README.md.template +38 -0
  73. package/src/generators/preset/files/tsconfig.json.template +6 -0
  74. package/src/generators/preset/nx-json.d.ts +4 -0
  75. package/src/generators/preset/nx-json.js +36 -0
  76. package/src/generators/preset/preset.d.ts +13 -0
  77. package/src/generators/preset/preset.js +113 -0
  78. package/src/generators/preset/schema.d.ts +4 -0
  79. package/src/generators/preset/schema.json +25 -0
  80. package/src/index.d.ts +2 -0
  81. package/src/index.js +19 -0
  82. package/tsconfig.lib.tsbuildinfo +1 -0
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.writePackageJson = writePackageJson;
37
+ const devkit_1 = require("@nx/devkit");
38
+ const path = __importStar(require("path"));
39
+ const TEMPLATE = (0, devkit_1.readJsonFile)(path.join(__dirname, 'template-package', 'package.json'));
40
+ function pickVersions(source, names) {
41
+ const result = {};
42
+ for (const name of names) {
43
+ const version = source?.[name];
44
+ if (version === undefined) {
45
+ throw new Error(`Missing "${name}" in template-package.json`);
46
+ }
47
+ result[name] = version;
48
+ }
49
+ return result;
50
+ }
51
+ const BASE_DEPS = pickVersions(TEMPLATE.dependencies, [
52
+ '@adobe/aio-sdk',
53
+ '@adobe/aio-lib-telemetry',
54
+ ]);
55
+ const COMMERCE_DEPS = pickVersions(TEMPLATE.dependencies, [
56
+ '@adobe/aio-commerce-lib-app',
57
+ '@adobe/aio-commerce-lib-config',
58
+ ]);
59
+ const ADMIN_UI_DEPS = pickVersions(TEMPLATE.dependencies, [
60
+ '@adobe/uix-guest',
61
+ '@adobe/exc-app',
62
+ '@adobe/react-spectrum',
63
+ 'react',
64
+ 'react-dom',
65
+ 'react-router',
66
+ ]);
67
+ const BASE_DEV_DEPS = pickVersions(TEMPLATE.devDependencies, [
68
+ '@aligent/ts-code-standards',
69
+ '@babel/preset-env',
70
+ '@babel/preset-typescript',
71
+ '@types/node',
72
+ 'babel-loader',
73
+ 'ts-loader',
74
+ 'type-fest',
75
+ 'typescript',
76
+ 'vitest',
77
+ ]);
78
+ const ADMIN_UI_DEV_DEPS = pickVersions(TEMPLATE.devDependencies, [
79
+ '@types/react',
80
+ '@types/react-dom',
81
+ ]);
82
+ function writePackageJson(tree, options) {
83
+ const dependencies = { ...BASE_DEPS };
84
+ const devDependencies = { ...BASE_DEV_DEPS };
85
+ const usesCommerceLib = options.hasAdminUI || options.hasBusinessConfig || options.hasCommerceWebhooks;
86
+ if (usesCommerceLib) {
87
+ Object.assign(dependencies, COMMERCE_DEPS);
88
+ }
89
+ if (options.hasAdminUI) {
90
+ Object.assign(dependencies, ADMIN_UI_DEPS);
91
+ Object.assign(devDependencies, ADMIN_UI_DEV_DEPS);
92
+ }
93
+ // Inline tsc invocations rather than going through `npm run` so the
94
+ // scripts (and the nx target that wraps them) work the same under npm,
95
+ // yarn, pnpm, etc. — none of them need a specific package manager binary
96
+ // to be on PATH.
97
+ const TYPECHECK_ACTIONS = 'tsc --noEmit --project src/actions/tsconfig.json';
98
+ const TYPECHECK_TESTS = 'tsc --noEmit --project tests/tsconfig.json';
99
+ const TYPECHECK_WEB = 'tsc --noEmit --project src/commerce-backend-ui-1/web-src/tsconfig.json';
100
+ const scripts = {
101
+ lint: 'eslint .',
102
+ 'lint:fix': 'eslint . --fix',
103
+ 'check-types:actions': TYPECHECK_ACTIONS,
104
+ 'check-types:tests': TYPECHECK_TESTS,
105
+ test: 'vitest run --passWithNoTests',
106
+ };
107
+ const checkTypeSteps = [TYPECHECK_ACTIONS];
108
+ if (options.hasAdminUI) {
109
+ scripts['check-types:web'] = TYPECHECK_WEB;
110
+ checkTypeSteps.push(TYPECHECK_WEB);
111
+ }
112
+ checkTypeSteps.push(TYPECHECK_TESTS);
113
+ scripts['check-types'] = checkTypeSteps.join(' && ');
114
+ const major = options.nodeVersion.split('.')[0];
115
+ const json = {
116
+ name: options.packageName,
117
+ version: '0.0.1',
118
+ description: options.description,
119
+ private: true,
120
+ type: 'commonjs',
121
+ scripts: orderScripts(scripts),
122
+ dependencies: sortObject(dependencies),
123
+ devDependencies: sortObject(devDependencies),
124
+ engines: { node: `>=${major}` },
125
+ nx: {
126
+ targets: {
127
+ 'check-types': {
128
+ executor: 'nx:run-commands',
129
+ options: { command: scripts['check-types'], cwd: '{projectRoot}' },
130
+ },
131
+ deploy: {
132
+ executor: 'nx:run-commands',
133
+ options: { command: 'aio app deploy', cwd: '{projectRoot}' },
134
+ },
135
+ },
136
+ },
137
+ };
138
+ tree.write(`${options.appRoot}/package.json`, JSON.stringify(json, null, 4) + '\n');
139
+ }
140
+ function sortObject(obj) {
141
+ return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a.localeCompare(b)));
142
+ }
143
+ function orderScripts(scripts) {
144
+ const order = [
145
+ 'lint',
146
+ 'lint:fix',
147
+ 'check-types',
148
+ 'check-types:actions',
149
+ 'check-types:web',
150
+ 'check-types:tests',
151
+ 'test',
152
+ ];
153
+ const ordered = {};
154
+ for (const key of order) {
155
+ const value = scripts[key];
156
+ if (value !== undefined)
157
+ ordered[key] = value;
158
+ }
159
+ for (const [key, value] of Object.entries(scripts)) {
160
+ if (!(key in ordered))
161
+ ordered[key] = value;
162
+ }
163
+ return ordered;
164
+ }
@@ -0,0 +1,3 @@
1
+ import type { Tree } from '@nx/devkit';
2
+ import type { AppGeneratorSchema, NormalizedSchema } from '../schema';
3
+ export declare function normalizeOptions(tree: Tree, options: AppGeneratorSchema): NormalizedSchema;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeOptions = normalizeOptions;
4
+ const SEMVER = /^v?(\d+\.\d+\.\d+)\s*$/m;
5
+ const DEFAULT_NODE_VERSION = '24.0.1';
6
+ const SIDEBAR_TITLES = {
7
+ catalog: 'Catalog Apps',
8
+ sales: 'Sales Apps',
9
+ customers: 'Customer Apps',
10
+ content: 'Content Apps',
11
+ };
12
+ function normalizeOptions(tree, options) {
13
+ // Name shape (kebab-case) is enforced by the schema's `pattern` field,
14
+ // which Nx validates before this function runs.
15
+ if (tree.exists(options.name)) {
16
+ throw new Error(`Path "${options.name}" already exists in the workspace.`);
17
+ }
18
+ const hasAdminUI = options.hasAdminUI ?? false;
19
+ const hasBusinessConfig = options.hasBusinessConfig ?? false;
20
+ const sidebarCategory = hasAdminUI
21
+ ? (options.sidebarCategory ?? 'none')
22
+ : 'none';
23
+ const displayName = options.displayName ?? toTitleCase(options.name);
24
+ const camel = toCamelCase(options.name);
25
+ return {
26
+ name: options.name,
27
+ description: options.description ?? '',
28
+ displayName,
29
+ hasAdminUI,
30
+ sidebarCategory,
31
+ hasBusinessConfig,
32
+ hasCommerceWebhooks: options.hasCommerceWebhooks ?? false,
33
+ hasEvents: options.hasEvents ?? false,
34
+ hasRestActions: options.hasRestActions ?? false,
35
+ hasScheduledActions: options.hasScheduledActions ?? false,
36
+ hasCustomInstallSteps: options.hasCustomInstallSteps ?? false,
37
+ appRoot: options.name,
38
+ packageName: `@aligent/${options.name}`,
39
+ runtimePackageName: camel,
40
+ appSlug: options.name.replace(/-/g, '_'),
41
+ extensionId: `${camel}Extension`,
42
+ sidebarCategoryTitle: sidebarCategory === 'none' ? '' : SIDEBAR_TITLES[sidebarCategory],
43
+ nodeVersion: readNodeVersion(tree),
44
+ };
45
+ }
46
+ /**
47
+ * Reads the workspace's `.nvmrc` and extracts the Node version. Falls back to
48
+ * a sensible default if the file is missing or doesn't contain a parseable
49
+ * semver — keeping the .nvmrc as the single source of truth without making
50
+ * the app generator brittle to non-AppBuilder workspaces.
51
+ */
52
+ function readNodeVersion(tree) {
53
+ const raw = tree.read('.nvmrc', 'utf-8');
54
+ if (raw === null)
55
+ return DEFAULT_NODE_VERSION;
56
+ const match = SEMVER.exec(raw);
57
+ return match?.[1] ?? DEFAULT_NODE_VERSION;
58
+ }
59
+ function toCamelCase(input) {
60
+ return input.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
61
+ }
62
+ function toTitleCase(input) {
63
+ return input
64
+ .split('-')
65
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
66
+ .join(' ');
67
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@aligent/nx-appbuilder-generated-app-deps",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "description": "Version pins for the deps that the app generator injects into a generated app's package.json. Tracked by Dependabot so version bumps land via PR; consumed at runtime by compose-package-json.ts.",
6
+ "dependencies": {
7
+ "@adobe/aio-sdk": "^6.0.0",
8
+ "@adobe/aio-lib-telemetry": "^1.1.3",
9
+ "@adobe/aio-commerce-lib-app": "^1.2.0",
10
+ "@adobe/aio-commerce-lib-config": "^1.1.0",
11
+ "@adobe/uix-guest": "^1.1.5",
12
+ "@adobe/exc-app": "^1.4.13",
13
+ "@adobe/react-spectrum": "^3.46.1",
14
+ "react": "^19.1.0",
15
+ "react-dom": "^19.1.0",
16
+ "react-router": "^7.13.0"
17
+ },
18
+ "devDependencies": {
19
+ "@aligent/ts-code-standards": "^4.2.0",
20
+ "@babel/preset-env": "^7.26.9",
21
+ "@babel/preset-typescript": "^7.27.0",
22
+ "@types/node": "^22.14.0",
23
+ "@types/react": "^19.1.0",
24
+ "@types/react-dom": "^19.1.2",
25
+ "babel-loader": "^10.0.0",
26
+ "ts-loader": "^9.5.2",
27
+ "type-fest": "^4.39.1",
28
+ "typescript": "^5.8.3",
29
+ "vitest": "^2.1.8"
30
+ }
31
+ }
@@ -0,0 +1,6 @@
1
+ import type { Tree } from '@nx/devkit';
2
+ import type { NormalizedSchema } from '../schema';
3
+ /**
4
+ * Adds the new app to the root package.json's workspaces array.
5
+ */
6
+ export declare function updateRootPackageJson(tree: Tree, options: NormalizedSchema): void;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateRootPackageJson = updateRootPackageJson;
4
+ /**
5
+ * Adds the new app to the root package.json's workspaces array.
6
+ */
7
+ function updateRootPackageJson(tree, options) {
8
+ const rootPath = 'package.json';
9
+ if (!tree.exists(rootPath)) {
10
+ throw new Error('No root package.json found — is this an Nx workspace?');
11
+ }
12
+ const raw = tree.read(rootPath, 'utf-8');
13
+ if (raw === null) {
14
+ throw new Error('Failed to read root package.json');
15
+ }
16
+ const json = JSON.parse(raw);
17
+ const workspaces = Array.isArray(json.workspaces) ? json.workspaces : [];
18
+ if (workspaces.includes(options.name))
19
+ return;
20
+ workspaces.push(options.name);
21
+ json.workspaces = workspaces;
22
+ tree.write(rootPath, JSON.stringify(json, null, 4) + '\n');
23
+ }
@@ -0,0 +1,8 @@
1
+ import type { Tree } from '@nx/devkit';
2
+ import type { NormalizedSchema } from '../schema';
3
+ /**
4
+ * Adds the new app to the workspace tsconfig.json's references array. Skips
5
+ * silently when the workspace tsconfig.json is absent so existing workspaces
6
+ * scaffolded before this template was added aren't forced to migrate.
7
+ */
8
+ export declare function addTsConfigReference(tree: Tree, options: NormalizedSchema): void;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addTsConfigReference = addTsConfigReference;
4
+ /**
5
+ * Adds the new app to the workspace tsconfig.json's references array. Skips
6
+ * silently when the workspace tsconfig.json is absent so existing workspaces
7
+ * scaffolded before this template was added aren't forced to migrate.
8
+ */
9
+ function addTsConfigReference(tree, options) {
10
+ const rootPath = 'tsconfig.json';
11
+ if (!tree.exists(rootPath))
12
+ return;
13
+ const raw = tree.read(rootPath, 'utf-8');
14
+ if (raw === null)
15
+ return;
16
+ const json = JSON.parse(raw);
17
+ const references = Array.isArray(json.references) ? json.references : [];
18
+ const refPath = `./${options.name}`;
19
+ if (references.some(ref => ref.path === refPath))
20
+ return;
21
+ references.push({ path: refPath });
22
+ json.references = references;
23
+ tree.write(rootPath, JSON.stringify(json, null, 4) + '\n');
24
+ }
@@ -0,0 +1,32 @@
1
+ export type SidebarCategory = 'catalog' | 'sales' | 'customers' | 'content' | 'none';
2
+
3
+ export interface AppGeneratorSchema {
4
+ name: string;
5
+ description?: string;
6
+ displayName?: string;
7
+ hasAdminUI?: boolean;
8
+ sidebarCategory?: SidebarCategory;
9
+ hasBusinessConfig?: boolean;
10
+ hasCommerceWebhooks?: boolean;
11
+ hasEvents?: boolean;
12
+ hasRestActions?: boolean;
13
+ hasScheduledActions?: boolean;
14
+ hasCustomInstallSteps?: boolean;
15
+ }
16
+
17
+ export interface NormalizedSchema extends Required<AppGeneratorSchema> {
18
+ /** Path of the generated app relative to the workspace root, e.g. "my-app" */
19
+ appRoot: string;
20
+ /** Scoped npm package name, e.g. "@aligent/my-app" */
21
+ packageName: string;
22
+ /** lower-camel-case identifier for runtime manifest packages */
23
+ runtimePackageName: string;
24
+ /** snake_case slug used inside the registration menu item id (e.g. "my_app") */
25
+ appSlug: string;
26
+ /** camelCase identifier with "Extension" suffix used as the EXTENSION_ID constant */
27
+ extensionId: string;
28
+ /** Title-cased section title for the sidebar (e.g. "Content Apps") */
29
+ sidebarCategoryTitle: string;
30
+ /** Full Node.js version read from the workspace's .nvmrc, e.g. "24.0.1" */
31
+ nodeVersion: string;
32
+ }
@@ -0,0 +1,73 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "$id": "AligentAppBuilderApp",
4
+ "title": "Adobe App Builder app",
5
+ "description": "Scaffolds a new Adobe App Builder app",
6
+ "type": "object",
7
+ "properties": {
8
+ "name": {
9
+ "type": "string",
10
+ "description": "App name (kebab-case, used as directory name and package name suffix)",
11
+ "$default": { "$source": "argv", "index": 0 },
12
+ "x-prompt": "What is the app name? (kebab-case, e.g. 'my-app')",
13
+ "pattern": "^[a-z][a-z0-9-]*$"
14
+ },
15
+ "description": {
16
+ "type": "string",
17
+ "description": "Short description of the app",
18
+ "x-prompt": "Short description of the app"
19
+ },
20
+ "displayName": {
21
+ "type": "string",
22
+ "description": "Human-readable display name (defaults to title-cased app name)"
23
+ },
24
+ "hasAdminUI": {
25
+ "type": "boolean",
26
+ "description": "Does the app need a Commerce admin UI (custom pages, sidebar menu items)?",
27
+ "default": false,
28
+ "x-prompt": "Will the app add an admin UI in Commerce (custom pages or menu items)?"
29
+ },
30
+ "sidebarCategory": {
31
+ "type": "string",
32
+ "description": "Commerce admin sidebar category for the menu item (only used when hasAdminUI=true). Prompted when hasAdminUI=true and the value isn't passed on the CLI.",
33
+ "enum": ["catalog", "sales", "customers", "content", "none"]
34
+ },
35
+ "hasBusinessConfig": {
36
+ "type": "boolean",
37
+ "description": "Does the app expose business configuration in the Commerce admin?",
38
+ "default": false,
39
+ "x-prompt": "Will the app store business configuration?"
40
+ },
41
+ "hasCommerceWebhooks": {
42
+ "type": "boolean",
43
+ "description": "Will the app receive Adobe Commerce webhooks? Implies the commerce lib (app management) is required.",
44
+ "default": false,
45
+ "x-prompt": "Will the app receive Adobe Commerce webhooks?"
46
+ },
47
+ "hasEvents": {
48
+ "type": "boolean",
49
+ "description": "Will the app subscribe to Adobe IO events?",
50
+ "default": false,
51
+ "x-prompt": "Will the app subscribe to Adobe IO events?"
52
+ },
53
+ "hasRestActions": {
54
+ "type": "boolean",
55
+ "description": "Will the app expose custom REST actions?",
56
+ "default": false,
57
+ "x-prompt": "Will the app expose custom REST actions?"
58
+ },
59
+ "hasScheduledActions": {
60
+ "type": "boolean",
61
+ "description": "Will the app run scheduled (cron-triggered) actions?",
62
+ "default": false,
63
+ "x-prompt": "Will the app run scheduled actions?"
64
+ },
65
+ "hasCustomInstallSteps": {
66
+ "type": "boolean",
67
+ "description": "Does the app need custom installation steps? (only relevant when commerce extensions are used)",
68
+ "default": false,
69
+ "x-prompt": "Does the app need custom installation steps?"
70
+ }
71
+ },
72
+ "required": ["name"]
73
+ }
@@ -0,0 +1,30 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Parcel
5
+ .parcel-cache/
6
+
7
+ # Nx
8
+ .nx/installation
9
+ .nx/cache
10
+ .nx/workspace-data
11
+
12
+ # Build outputs
13
+ dist/
14
+
15
+ # IDE
16
+ .idea/
17
+ .vscode/
18
+
19
+ # OS
20
+ .DS_Store
21
+
22
+ # Logs
23
+ *.log
24
+
25
+ # Environment
26
+ .env
27
+ .env.local
28
+
29
+ # Adobe AppBuilder
30
+ .aio
@@ -0,0 +1,2 @@
1
+ @aligent:registry=https://npm.corp.aligent.consulting/
2
+ //npm.corp.aligent.consulting/:_authToken=${NPM_TOKEN}
@@ -0,0 +1 @@
1
+ v<%= nodeVersion %>
@@ -0,0 +1,38 @@
1
+ # <%= name %>
2
+
3
+ An Aligent Adobe App Builder monorepo, scaffolded with `@aligent/nx-appbuilder`.
4
+
5
+ ## Prerequisites
6
+
7
+ This monorepo uses packages from the Aligent private npm registry at
8
+ `https://npm.corp.aligent.consulting/`. Set `NPM_TOKEN` in your shell before
9
+ installing dependencies:
10
+
11
+ ```bash
12
+ export NPM_TOKEN=<your-token>
13
+ ```
14
+
15
+ (Generate the token by signing in to the registry with your GitHub account.)
16
+
17
+ Then install with whichever package manager you prefer — `npm install`,
18
+ `yarn install`, or `pnpm install` all work.
19
+
20
+ ## Adding a new app
21
+
22
+ ```bash
23
+ npx nx g @aligent/nx-appbuilder:app <app-name>
24
+ ```
25
+
26
+ The generator will prompt for the app's shape (admin UI, business config,
27
+ events, scheduled actions, etc.) and scaffold the appropriate files.
28
+
29
+ ## Day-to-day commands
30
+
31
+ ```bash
32
+ npx nx affected -t lint # lint affected projects
33
+ npx nx run-many -t lint # lint every project
34
+ npx nx affected -t test # test affected projects
35
+ npx nx affected -t check-types # type-check affected projects
36
+ npx nx run <app>:deploy # deploy a specific app via aio
37
+ npx nx graph # visualise the project graph
38
+ ```
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "@aligent/ts-code-standards/tsconfigs-extend",
3
+ "compileOnSave": false,
4
+ "files": [],
5
+ "references": []
6
+ }
@@ -0,0 +1,4 @@
1
+ import type { NxJsonConfiguration } from '@nx/devkit';
2
+ export declare const NX_JSON: NxJsonConfiguration & {
3
+ $schema: string;
4
+ };
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NX_JSON = void 0;
4
+ exports.NX_JSON = {
5
+ $schema: './node_modules/nx/schemas/nx-schema.json',
6
+ defaultBase: 'origin/main',
7
+ installation: {
8
+ version: '22.4.5',
9
+ },
10
+ plugins: [
11
+ { plugin: '@nx/eslint/plugin', options: {} },
12
+ // App Builder apps drive their own multi-tsconfig type-checking via a
13
+ // `check-types` script (one tsc invocation per actions/web/tests
14
+ // subtree). The plugin's inferred `typecheck` target only runs against
15
+ // a single root tsconfig, so it's disabled here to avoid surfacing a
16
+ // useless target alongside our custom one.
17
+ { plugin: '@nx/js/typescript', options: { build: false, typecheck: false } },
18
+ { plugin: '@nx/vitest', options: {} },
19
+ ],
20
+ namedInputs: {
21
+ default: ['{projectRoot}/**/*', 'sharedGlobals'],
22
+ sharedGlobals: [],
23
+ production: [
24
+ 'default',
25
+ '!{projectRoot}/**/*.spec.ts',
26
+ '!{projectRoot}/**/*.test.ts',
27
+ '!{projectRoot}/tests/**/*',
28
+ ],
29
+ },
30
+ targetDefaults: {
31
+ lint: { inputs: ['default'], cache: true },
32
+ 'check-types': { inputs: ['default'], cache: true },
33
+ test: { inputs: ['default'], cache: true },
34
+ build: { inputs: ['production'], cache: true, dependsOn: ['^build'] },
35
+ },
36
+ };
@@ -0,0 +1,13 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ import type { PresetGeneratorSchema } from './schema';
3
+ /**
4
+ * Preset generator invoked by `create-nx-workspace --preset=@aligent/nx-appbuilder`.
5
+ *
6
+ * Scaffolds the workspace shell — root package.json, nx.json, .npmrc, etc. —
7
+ * but does NOT scaffold any apps. Apps are added afterwards via the `app`
8
+ * generator (`npx nx g @aligent/nx-appbuilder:app <name>`).
9
+ *
10
+ * Name shape (kebab-case) and nodeVersion semver are enforced by the schema's
11
+ * `pattern` fields before this function runs.
12
+ */
13
+ export default function presetGenerator(tree: Tree, options: PresetGeneratorSchema): Promise<void>;