@vendure-platform/create 0.3.0 → 0.5.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.
- package/CHANGELOG.md +8 -0
- package/README.md +7 -7
- package/dist/add-to-existing.js +1 -583
- package/dist/assets/storefront/messages/de.json +2 -0
- package/dist/assets/storefront/messages/en.json +2 -0
- package/dist/assets/storefront/package.json +1 -1
- package/dist/assets/storefront/src/app/[locale]/(catalog)/product/[slug]/page.tsx +7 -2
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/activity-feed.tsx +152 -0
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/add-item-search.tsx +130 -0
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/add-member-form.tsx +124 -0
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/members-panel.tsx +240 -0
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/page.tsx +47 -0
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/rename-dialog.tsx +96 -0
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/shared-cart-detail-client.tsx +555 -0
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/actions.ts +260 -0
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/new/new-shared-cart-form.tsx +77 -0
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/new/page.tsx +47 -0
- package/dist/assets/storefront/src/app/[locale]/account/shared-carts/page.tsx +263 -0
- package/dist/assets/storefront/src/app/[locale]/cart/cart.tsx +12 -1
- package/dist/assets/storefront/src/app/[locale]/cart/order-summary.tsx +23 -0
- package/dist/assets/storefront/src/components/commerce/account-nav-items.ts +2 -0
- package/dist/assets/storefront/src/components/commerce/add-to-shared-cart.tsx +225 -0
- package/dist/assets/storefront/src/components/commerce/product-info.tsx +14 -1
- package/dist/assets/storefront/src/components/commerce/shared-cart-role.ts +39 -0
- package/dist/assets/storefront/src/components/commerce/shared-cart-status-badge.tsx +24 -0
- package/dist/assets/storefront/src/graphql-env.d.ts +28 -15
- package/dist/assets/storefront/src/lib/vendure/api.ts +8 -4
- package/dist/assets/storefront/src/lib/vendure/mutations.ts +96 -0
- package/dist/assets/storefront/src/lib/vendure/queries.ts +142 -0
- package/dist/assets/storefront/src/schema.graphql +321 -61
- package/dist/bin/run.js +1 -119
- package/dist/cli.js +1 -309
- package/dist/git-init.js +1 -60
- package/dist/index.js +1 -19
- package/dist/plugin-registry.js +1 -203
- package/dist/registry.js +1 -29
- package/dist/scaffold-shared.js +1 -124
- package/dist/scaffold-storefront-only.js +1 -101
- package/dist/scaffolder.js +1 -203
- package/dist/sort-package-json.js +1 -26
- package/dist/storefront-copier.js +1 -149
- package/dist/template-renderer.js +1 -221
- package/dist/types.js +1 -3
- package/package.json +5 -4
- package/dist/add-to-existing.js.map +0 -1
- package/dist/assets/storefront/src/lib/quantity.test.js +0 -20
- package/dist/bin/run.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/git-init.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/plugin-registry.js.map +0 -1
- package/dist/registry.js.map +0 -1
- package/dist/scaffold-shared.js.map +0 -1
- package/dist/scaffold-storefront-only.js.map +0 -1
- package/dist/scaffolder.js.map +0 -1
- package/dist/sort-package-json.js.map +0 -1
- package/dist/storefront-copier.js.map +0 -1
- package/dist/template-renderer.js.map +0 -1
- package/dist/types.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.5.0 (2026-08-04)
|
|
2
|
+
|
|
3
|
+
Version bump only — no functional changes in @vendure-platform/create.
|
|
4
|
+
|
|
5
|
+
## 0.4.0 (2026-07-03)
|
|
6
|
+
|
|
7
|
+
Version bump only — no functional changes in @vendure-platform/create.
|
|
8
|
+
|
|
1
9
|
## 0.3.0 (2026-06-29)
|
|
2
10
|
|
|
3
11
|
Version bump only — no functional changes in @vendure-platform/create.
|
package/README.md
CHANGED
|
@@ -36,10 +36,10 @@ When `--plugins` and `--company` are both provided, the CLI runs in non-interact
|
|
|
36
36
|
|
|
37
37
|
## Tokens: registry vs license
|
|
38
38
|
|
|
39
|
-
The Vendure Enterprise Portal issues **two distinct tokens** with different purposes
|
|
39
|
+
The Vendure Enterprise Portal issues **two distinct tokens** with different purposes - keep them straight:
|
|
40
40
|
|
|
41
|
-
- **Registry token
|
|
42
|
-
- **License token
|
|
41
|
+
- **Registry token**: npm auth token for the private registry. Lets `${pm} install` download `@vendure-platform/*` packages. The CLI writes it into the project `.npmrc` as `_authToken`. `.npmrc` is gitignored.
|
|
42
|
+
- **License token**: checked at server boot by the License Guard plugin. The CLI writes it into `.env` as `VENDURE_PLATFORM_LICENSE_TOKEN`.
|
|
43
43
|
|
|
44
44
|
They are not interchangeable. Pass each via its dedicated flag (`--registry-token`, `--license-token`) or paste each at its own interactive prompt. Either can be skipped (blank input) if you want to add it later.
|
|
45
45
|
|
|
@@ -47,9 +47,9 @@ They are not interchangeable. Pass each via its dedicated flag (`--registry-toke
|
|
|
47
47
|
|
|
48
48
|
Plugins fall into three tiers (mirroring `@vendure-platform/plugin-meta`):
|
|
49
49
|
|
|
50
|
-
- **Core
|
|
51
|
-
- **Optional
|
|
52
|
-
- **Requires config
|
|
50
|
+
- **Core**: always active, can't be disabled. Hidden from the interactive prompt.
|
|
51
|
+
- **Optional**: active by default. Pre-ticked in the prompt; deselect to emit `<key>: false` in the generated `vendure-config.ts`.
|
|
52
|
+
- **Requires config**: inactive by default. Pick from the prompt to enable; the generated config carries the env-var-driven options block.
|
|
53
53
|
|
|
54
54
|
| Key | Plugin | Category | Tier |
|
|
55
55
|
|-----|--------|----------|------|
|
|
@@ -77,7 +77,7 @@ The canonical list lives in `libs/plugin-meta/src/index.ts`; this table mirrors
|
|
|
77
77
|
|
|
78
78
|
## Dependencies
|
|
79
79
|
|
|
80
|
-
Inter-plugin dependencies are resolved by `VendurePlatform.init()` at runtime
|
|
80
|
+
Inter-plugin dependencies are resolved by `VendurePlatform.init()` at runtime - not by the scaffolder. Selecting `approval-workflows` will activate `org-hierarchy` and `workflow-engine` automatically (they're core anyway). Selecting `global-search` will activate `advanced-search` (also core). Integration sub-plugins between active pairs are wired automatically.
|
|
81
81
|
|
|
82
82
|
## After Scaffolding
|
|
83
83
|
|
package/dist/add-to-existing.js
CHANGED
|
@@ -1,583 +1 @@
|
|
|
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.detectExistingProject = detectExistingProject;
|
|
37
|
-
exports.applyAddToExisting = applyAddToExisting;
|
|
38
|
-
exports.runAddToExistingCli = runAddToExistingCli;
|
|
39
|
-
exports.addToExisting = addToExisting;
|
|
40
|
-
exports.formatChecklist = formatChecklist;
|
|
41
|
-
const fs = __importStar(require("fs-extra"));
|
|
42
|
-
const path = __importStar(require("path"));
|
|
43
|
-
const p = __importStar(require("@clack/prompts"));
|
|
44
|
-
const plugin_registry_1 = require("./plugin-registry");
|
|
45
|
-
const registry_1 = require("./registry");
|
|
46
|
-
const template_renderer_1 = require("./template-renderer");
|
|
47
|
-
const INSTALLATION_GUIDE_FILENAME = 'vendure-platform-installation-guide.md';
|
|
48
|
-
/**
|
|
49
|
-
* Detect the layout of an existing Vendure project.
|
|
50
|
-
*
|
|
51
|
-
* We look for `@vendure/core` in `package.json` and a `vendure-config.ts` file
|
|
52
|
-
* somewhere under `src/`. We don't enforce a specific layout — if we can't
|
|
53
|
-
* find the config we still write the installation guide, just to the root.
|
|
54
|
-
*/
|
|
55
|
-
async function detectExistingProject(projectDir) {
|
|
56
|
-
var _a, _b;
|
|
57
|
-
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
58
|
-
if (!(await fs.pathExists(packageJsonPath))) {
|
|
59
|
-
throw new Error(`No package.json found at ${packageJsonPath}. Run this from your Vendure project root.`);
|
|
60
|
-
}
|
|
61
|
-
const pkg = await fs.readJson(packageJsonPath);
|
|
62
|
-
const deps = { ...((_a = pkg.dependencies) !== null && _a !== void 0 ? _a : {}), ...((_b = pkg.devDependencies) !== null && _b !== void 0 ? _b : {}) };
|
|
63
|
-
const hasVendureCore = '@vendure/core' in deps;
|
|
64
|
-
// Search a few likely locations for vendure-config.ts. Customers vary —
|
|
65
|
-
// some use src/, some use server/src/. We try the common spots; if we
|
|
66
|
-
// can't find one we surface that to the user but keep going.
|
|
67
|
-
const configCandidates = [
|
|
68
|
-
path.join(projectDir, 'src', 'vendure-config.ts'),
|
|
69
|
-
path.join(projectDir, 'server', 'src', 'vendure-config.ts'),
|
|
70
|
-
path.join(projectDir, 'src', 'vendure-config.js'),
|
|
71
|
-
];
|
|
72
|
-
let vendureConfigPath = null;
|
|
73
|
-
for (const candidate of configCandidates) {
|
|
74
|
-
if (await fs.pathExists(candidate)) {
|
|
75
|
-
vendureConfigPath = candidate;
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return {
|
|
80
|
-
projectDir,
|
|
81
|
-
packageJsonPath,
|
|
82
|
-
vendureConfigPath,
|
|
83
|
-
hasVendureCore,
|
|
84
|
-
envPath: path.join(projectDir, '.env'),
|
|
85
|
-
npmrcPath: path.join(projectDir, '.npmrc'),
|
|
86
|
-
gitignorePath: path.join(projectDir, '.gitignore'),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Apply the safe-to-modify changes:
|
|
91
|
-
* 1. Add `@vendure-platform/platform` and any selected requires-config
|
|
92
|
-
* plugin packages to `package.json` dependencies.
|
|
93
|
-
* 2. Append missing env vars to `.env` (idempotent — never overwrite values).
|
|
94
|
-
* 3. Ensure `.npmrc` declares the `@vendure-platform` scope.
|
|
95
|
-
* 4. Write a `vendure-platform-installation-guide.md` in the project root
|
|
96
|
-
* containing the exact import + spread to paste into `vendure-config.ts`.
|
|
97
|
-
*
|
|
98
|
-
* Returns a checklist of next steps to print at the end.
|
|
99
|
-
*/
|
|
100
|
-
async function applyAddToExisting(detected, options) {
|
|
101
|
-
const { selectedPlugins, dryRun, registryToken, licenseToken } = options;
|
|
102
|
-
const resolvedKeys = (0, plugin_registry_1.resolveActivePluginKeys)(selectedPlugins);
|
|
103
|
-
const resolvedPlugins = resolvedKeys.map((k) => (0, plugin_registry_1.getPlugin)(k));
|
|
104
|
-
const versionSpec = (0, template_renderer_1.resolvePluginVersionSpec)();
|
|
105
|
-
const checklist = [];
|
|
106
|
-
// 1. package.json — add `@vendure-platform/platform` AND each resolved
|
|
107
|
-
// plugin's package as a direct dep. Listing only `platform` would
|
|
108
|
-
// work on npm/bun (which hoist transitives) but break under
|
|
109
|
-
// pnpm strict mode, and would also leave the user's snippet
|
|
110
|
-
// imports like `import { SqlAnalyticsStrategy } from
|
|
111
|
-
// '@vendure-platform/advanced-search'` looking at an undeclared
|
|
112
|
-
// dependency. This matches what the fresh-scaffold flow writes.
|
|
113
|
-
//
|
|
114
|
-
// We intentionally do NOT add `@vendure-platform/data-populator`,
|
|
115
|
-
// `integration`, or `scenario-default` here — those are
|
|
116
|
-
// scaffold-specific (used by the generated populate.ts boot code)
|
|
117
|
-
// and irrelevant to an existing project the user is patching.
|
|
118
|
-
const pluginPackageNames = resolvedPlugins.map((p) => p.packageName);
|
|
119
|
-
const addedDeps = await patchPackageJson(detected.packageJsonPath, versionSpec, pluginPackageNames, dryRun);
|
|
120
|
-
if (addedDeps.length > 0) {
|
|
121
|
-
const summary = addedDeps.length === 1
|
|
122
|
-
? addedDeps[0]
|
|
123
|
-
: `${addedDeps.length} packages (${addedDeps[0]}, …)`;
|
|
124
|
-
checklist.push(`Added ${summary} at ${versionSpec} to package.json — run \`npm install\` (or your package manager equivalent).`);
|
|
125
|
-
}
|
|
126
|
-
// 2. .env — append missing env vars from selected plugins. If we have a
|
|
127
|
-
// license token, seed it as the default value for VENDURE_PLATFORM_LICENSE_TOKEN
|
|
128
|
-
// so the user doesn't have to paste it twice.
|
|
129
|
-
const envAdditions = collectEnvAdditions(resolvedPlugins, licenseToken);
|
|
130
|
-
const appendedCount = await appendMissingEnvVars(detected.envPath, envAdditions, dryRun);
|
|
131
|
-
if (appendedCount > 0) {
|
|
132
|
-
checklist.push(`Appended ${appendedCount} env var(s) to .env — fill in real values before booting.`);
|
|
133
|
-
}
|
|
134
|
-
// 2a. Recovery path: if the user previously ran `create add` without a
|
|
135
|
-
// token (leaving `VENDURE_PLATFORM_LICENSE_TOKEN=` empty in .env)
|
|
136
|
-
// and is now re-running with a token, fill that empty value in.
|
|
137
|
-
// Never overwrite a non-empty value — that's still the user's
|
|
138
|
-
// intentional setting.
|
|
139
|
-
if (licenseToken) {
|
|
140
|
-
const filled = await fillEmptyLicenseTokenInEnv(detected.envPath, licenseToken, dryRun);
|
|
141
|
-
if (filled) {
|
|
142
|
-
checklist.push(`Filled in the empty VENDURE_PLATFORM_LICENSE_TOKEN value in .env.`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
// 3. .npmrc — declare the @vendure-platform scope, and (if a registry
|
|
146
|
-
// token was provided) the `_authToken` line so `${pm} install` works
|
|
147
|
-
// without any `~/.npmrc` setup. The token is the literal value, not
|
|
148
|
-
// env-var indirection — npm cannot read `.env` during install, so
|
|
149
|
-
// indirection would only work when the user manually exports the env
|
|
150
|
-
// var. The project `.gitignore` is updated below to keep this file
|
|
151
|
-
// untracked.
|
|
152
|
-
const npmrcResult = await ensureNpmrcScopeAndAuth(detected.npmrcPath, registryToken, dryRun);
|
|
153
|
-
if (npmrcResult.scopeAdded || npmrcResult.authAdded) {
|
|
154
|
-
const bits = [];
|
|
155
|
-
if (npmrcResult.scopeAdded)
|
|
156
|
-
bits.push('scope');
|
|
157
|
-
if (npmrcResult.authAdded)
|
|
158
|
-
bits.push('auth token');
|
|
159
|
-
checklist.push(`Updated .npmrc (${bits.join(' + ')}).`);
|
|
160
|
-
}
|
|
161
|
-
// 3a. .gitignore — make sure .npmrc never gets committed. We do this
|
|
162
|
-
// unconditionally (even without a token) so future runs that add a
|
|
163
|
-
// token to the existing scope-only .npmrc don't accidentally commit
|
|
164
|
-
// it. Without a token in play the entry is harmless either way.
|
|
165
|
-
const gitignoreAdded = await ensureGitignoreEntry(detected.gitignorePath, '.npmrc', dryRun);
|
|
166
|
-
if (gitignoreAdded) {
|
|
167
|
-
checklist.push(`Added .npmrc to .gitignore so any future registry token never gets committed.`);
|
|
168
|
-
}
|
|
169
|
-
// 4. vendure-platform-installation-guide.md — generate paste-in
|
|
170
|
-
// instructions. Always written to the project root (not next to the
|
|
171
|
-
// config) so it's easy to find regardless of project layout.
|
|
172
|
-
const guide = renderInstallationGuide(resolvedPlugins, resolvedKeys);
|
|
173
|
-
const guidePath = path.join(detected.projectDir, INSTALLATION_GUIDE_FILENAME);
|
|
174
|
-
if (!dryRun) {
|
|
175
|
-
await fs.writeFile(guidePath, guide);
|
|
176
|
-
}
|
|
177
|
-
checklist.push(`Wrote ${path.relative(detected.projectDir, guidePath)} — follow it to wire up your vendure-config.ts.`);
|
|
178
|
-
// 5. Downstream reminders (not automated)
|
|
179
|
-
// Bootstrap-import swap is the gate: without it, every platform plugin fails
|
|
180
|
-
// at startup with LICENSE_GUARD_NONCE_MISMATCH. Surface it as its own line so
|
|
181
|
-
// it can't be missed by anyone who only skims the next-steps printout.
|
|
182
|
-
checklist.push(`Swap \`import { bootstrap } from '@vendure/core'\` for \`'@vendure-platform/platform'\` in your server entry file (and \`bootstrapWorker\` if you have a worker). See the installation guide's "Bootstrap import" section.`);
|
|
183
|
-
checklist.push('Generate and run a migration for the new platform entities.');
|
|
184
|
-
checklist.push('Rebuild the dashboard if you serve a pre-built artefact.');
|
|
185
|
-
checklist.push('Grant new permissions to existing admin roles via Settings → Roles.');
|
|
186
|
-
return checklist;
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Add `@vendure-platform/platform` plus each resolved plugin package to
|
|
190
|
-
* `package.json` dependencies (idempotent — already-present packages are
|
|
191
|
-
* left at their existing version, never downgraded). Returns the list of
|
|
192
|
-
* packages we actually added so the caller can report a useful checklist
|
|
193
|
-
* line and skip the message entirely when nothing changed.
|
|
194
|
-
*/
|
|
195
|
-
async function patchPackageJson(packageJsonPath, versionSpec, pluginPackageNames, dryRun) {
|
|
196
|
-
var _a;
|
|
197
|
-
const pkg = await fs.readJson(packageJsonPath);
|
|
198
|
-
(_a = pkg.dependencies) !== null && _a !== void 0 ? _a : (pkg.dependencies = {});
|
|
199
|
-
// Sort so the checklist message is deterministic and the platform
|
|
200
|
-
// meta-package always lands first (it's the "headline" dep).
|
|
201
|
-
const allPackages = ['@vendure-platform/platform', ...pluginPackageNames]
|
|
202
|
-
.filter((name, i, arr) => arr.indexOf(name) === i);
|
|
203
|
-
const added = [];
|
|
204
|
-
for (const name of allPackages) {
|
|
205
|
-
if (!pkg.dependencies[name]) {
|
|
206
|
-
pkg.dependencies[name] = versionSpec;
|
|
207
|
-
added.push(name);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
if (added.length > 0 && !dryRun) {
|
|
211
|
-
await fs.writeJson(packageJsonPath, pkg, { spaces: 2 });
|
|
212
|
-
}
|
|
213
|
-
return added;
|
|
214
|
-
}
|
|
215
|
-
function collectEnvAdditions(plugins, licenseToken) {
|
|
216
|
-
// Always include the license guard vars even if the plugin isn't selected
|
|
217
|
-
// — they're required for boot.
|
|
218
|
-
const additions = [
|
|
219
|
-
{ name: 'VENDURE_PLATFORM_LICENSE_TOKEN', defaultValue: licenseToken !== null && licenseToken !== void 0 ? licenseToken : '' },
|
|
220
|
-
{ name: 'VENDURE_PLATFORM_LICENSE_GUARD_LOCAL_DEV', defaultValue: '1' },
|
|
221
|
-
];
|
|
222
|
-
for (const pl of plugins) {
|
|
223
|
-
for (const v of pl.envVars) {
|
|
224
|
-
if (!additions.some((a) => a.name === v.name)) {
|
|
225
|
-
additions.push(v);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
return additions;
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Find a `VENDURE_PLATFORM_LICENSE_TOKEN=` line with an empty value and
|
|
233
|
-
* fill it in with `token`. Used to recover from a previous `create add` run
|
|
234
|
-
* that didn't have a token to hand.
|
|
235
|
-
*
|
|
236
|
-
* - `VENDURE_PLATFORM_LICENSE_TOKEN=` → updated to `=<token>`
|
|
237
|
-
* - `VENDURE_PLATFORM_LICENSE_TOKEN=preexisting`→ left alone
|
|
238
|
-
* - `# VENDURE_PLATFORM_LICENSE_TOKEN=` → left alone (commented out)
|
|
239
|
-
*
|
|
240
|
-
* Returns `true` if the file was modified.
|
|
241
|
-
*/
|
|
242
|
-
async function fillEmptyLicenseTokenInEnv(envPath, token, dryRun) {
|
|
243
|
-
if (!(await fs.pathExists(envPath)))
|
|
244
|
-
return false;
|
|
245
|
-
const existing = await fs.readFile(envPath, 'utf8');
|
|
246
|
-
const lines = existing.split('\n');
|
|
247
|
-
let modified = false;
|
|
248
|
-
const TOKEN_KEY = 'VENDURE_PLATFORM_LICENSE_TOKEN';
|
|
249
|
-
for (let i = 0; i < lines.length; i++) {
|
|
250
|
-
const trimmed = lines[i].trim();
|
|
251
|
-
if (trimmed.startsWith('#'))
|
|
252
|
-
continue;
|
|
253
|
-
if (trimmed === `${TOKEN_KEY}=`) {
|
|
254
|
-
lines[i] = `${TOKEN_KEY}=${token}`;
|
|
255
|
-
modified = true;
|
|
256
|
-
// Only fill the first occurrence — dotenv reads top-down and any
|
|
257
|
-
// subsequent line would be a duplicate the user authored deliberately.
|
|
258
|
-
break;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
if (modified && !dryRun) {
|
|
262
|
-
await fs.writeFile(envPath, lines.join('\n'));
|
|
263
|
-
}
|
|
264
|
-
return modified;
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Append any env vars from `additions` that aren't already declared in
|
|
268
|
-
* `.env`. Idempotent — never overwrites or duplicates an existing key.
|
|
269
|
-
* Returns the count of keys actually appended, so callers can decide
|
|
270
|
-
* whether to surface a "we did something" message.
|
|
271
|
-
*/
|
|
272
|
-
async function appendMissingEnvVars(envPath, additions, dryRun) {
|
|
273
|
-
let existing = '';
|
|
274
|
-
if (await fs.pathExists(envPath)) {
|
|
275
|
-
existing = await fs.readFile(envPath, 'utf8');
|
|
276
|
-
}
|
|
277
|
-
const existingKeys = new Set(existing
|
|
278
|
-
.split('\n')
|
|
279
|
-
.map((line) => { var _a; return (_a = line.split('=')[0]) === null || _a === void 0 ? void 0 : _a.trim(); })
|
|
280
|
-
.filter((k) => Boolean(k) && !k.startsWith('#')));
|
|
281
|
-
const toAdd = additions.filter((a) => !existingKeys.has(a.name));
|
|
282
|
-
if (toAdd.length === 0)
|
|
283
|
-
return 0;
|
|
284
|
-
const header = '\n# Added by @vendure-platform/create add\n';
|
|
285
|
-
const block = toAdd.map((a) => `${a.name}=${a.defaultValue}`).join('\n') + '\n';
|
|
286
|
-
if (!dryRun) {
|
|
287
|
-
const trailing = existing.endsWith('\n') || existing === '' ? '' : '\n';
|
|
288
|
-
await fs.writeFile(envPath, existing + trailing + header + block);
|
|
289
|
-
}
|
|
290
|
-
return toAdd.length;
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Ensure the project-level `.npmrc` declares both the `@vendure-platform`
|
|
294
|
-
* scope and (when a registry token is supplied) a registry-scoped
|
|
295
|
-
* `_authToken` line. The registry token is the npm auth token from the
|
|
296
|
-
* Enterprise Portal — distinct from the server-side license token, which
|
|
297
|
-
* lives in `.env` and is handled by the env-writing path.
|
|
298
|
-
*
|
|
299
|
-
* The auth line uses the **literal token value**, not env-var indirection.
|
|
300
|
-
* npm reads `.npmrc` at install time and only resolves `${VAR}` against the
|
|
301
|
-
* process environment — it doesn't load `.env` files. Env-var indirection
|
|
302
|
-
* would therefore only work when the user has manually exported the var,
|
|
303
|
-
* which defeats the point of bundling the token at scaffold time. Project
|
|
304
|
-
* `.gitignore` is updated separately to keep this file untracked.
|
|
305
|
-
*
|
|
306
|
-
* Idempotent: lines that already exist are left alone.
|
|
307
|
-
*/
|
|
308
|
-
async function ensureNpmrcScopeAndAuth(npmrcPath, registryToken, dryRun) {
|
|
309
|
-
const registryUrl = (0, registry_1.getRegistryUrl)();
|
|
310
|
-
const registryHost = (0, registry_1.getRegistryHostname)();
|
|
311
|
-
const scopeLine = `@vendure-platform:registry=${registryUrl}`;
|
|
312
|
-
// `npm login` writes the auth-token line with a leading `//` and a
|
|
313
|
-
// trailing slash before `:_authToken`. We match that convention so a
|
|
314
|
-
// subsequent `npm login` / `npm logout` rewrite cleanly.
|
|
315
|
-
const authLineKey = `//${registryHost}/:_authToken=`;
|
|
316
|
-
let existing = '';
|
|
317
|
-
if (await fs.pathExists(npmrcPath)) {
|
|
318
|
-
existing = await fs.readFile(npmrcPath, 'utf8');
|
|
319
|
-
}
|
|
320
|
-
const hasScope = existing.includes('@vendure-platform:registry=');
|
|
321
|
-
const hasAuth = existing.includes(authLineKey);
|
|
322
|
-
const linesToAdd = [];
|
|
323
|
-
if (!hasScope)
|
|
324
|
-
linesToAdd.push(scopeLine);
|
|
325
|
-
if (registryToken && !hasAuth)
|
|
326
|
-
linesToAdd.push(`${authLineKey}${registryToken}`);
|
|
327
|
-
if (linesToAdd.length === 0) {
|
|
328
|
-
return { scopeAdded: false, authAdded: false };
|
|
329
|
-
}
|
|
330
|
-
const trailing = existing === '' || existing.endsWith('\n') ? '' : '\n';
|
|
331
|
-
if (!dryRun) {
|
|
332
|
-
await fs.writeFile(npmrcPath, existing + trailing + linesToAdd.join('\n') + '\n');
|
|
333
|
-
}
|
|
334
|
-
return {
|
|
335
|
-
scopeAdded: !hasScope,
|
|
336
|
-
authAdded: Boolean(registryToken) && !hasAuth,
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Ensure `entry` appears as its own line in `.gitignore`. Skips if the entry
|
|
341
|
-
* (or a less-specific glob that would match it) is already present. Creates
|
|
342
|
-
* the file when missing.
|
|
343
|
-
*/
|
|
344
|
-
async function ensureGitignoreEntry(gitignorePath, entry, dryRun) {
|
|
345
|
-
let existing = '';
|
|
346
|
-
if (await fs.pathExists(gitignorePath)) {
|
|
347
|
-
existing = await fs.readFile(gitignorePath, 'utf8');
|
|
348
|
-
}
|
|
349
|
-
const lines = existing.split('\n').map((l) => l.trim());
|
|
350
|
-
if (lines.includes(entry) || lines.includes(`/${entry}`)) {
|
|
351
|
-
return false;
|
|
352
|
-
}
|
|
353
|
-
const trailing = existing === '' || existing.endsWith('\n') ? '' : '\n';
|
|
354
|
-
if (!dryRun) {
|
|
355
|
-
await fs.writeFile(gitignorePath, existing + trailing + entry + '\n');
|
|
356
|
-
}
|
|
357
|
-
return true;
|
|
358
|
-
}
|
|
359
|
-
function renderInstallationGuide(plugins, resolvedKeys) {
|
|
360
|
-
const imports = [`import { VendurePlatform } from '@vendure-platform/platform';`];
|
|
361
|
-
const optionsBlocks = [];
|
|
362
|
-
for (const pl of plugins) {
|
|
363
|
-
if (pl.platformImports)
|
|
364
|
-
imports.push(...pl.platformImports);
|
|
365
|
-
if (pl.platformOptionsBlock) {
|
|
366
|
-
optionsBlocks.push(` ${pl.platformOptionsBlock},`);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
// Plugins that are optional but the user didn't pick → emit `key: false`
|
|
370
|
-
const disabledKeys = plugin_registry_1.pluginRegistry
|
|
371
|
-
.filter((pl) => pl.tier === 'optional' && !resolvedKeys.includes(pl.key))
|
|
372
|
-
.map((pl) => pl.key);
|
|
373
|
-
for (const key of disabledKeys) {
|
|
374
|
-
const platformKey = (0, plugin_registry_1.getPlugin)(key).platformKey;
|
|
375
|
-
optionsBlocks.push(` ${platformKey}: false,`);
|
|
376
|
-
}
|
|
377
|
-
const importsText = imports.join('\n');
|
|
378
|
-
const optionsText = optionsBlocks.length === 0
|
|
379
|
-
? ' // All optional plugins enabled with default config'
|
|
380
|
-
: optionsBlocks.join('\n');
|
|
381
|
-
return `# Vendure Platform installation guide
|
|
382
|
-
|
|
383
|
-
Paste these changes into your existing project. Step 1 is the most important —
|
|
384
|
-
without it, every Vendure Platform plugin refuses to start with
|
|
385
|
-
\`LICENSE_GUARD_NONCE_MISMATCH\`.
|
|
386
|
-
|
|
387
|
-
## 1. Bootstrap import (server entry point)
|
|
388
|
-
|
|
389
|
-
In your server entry file (typically \`src/index.ts\` or wherever you call
|
|
390
|
-
\`bootstrap()\`), swap the bootstrap import from \`@vendure/core\` to
|
|
391
|
-
\`@vendure-platform/platform\`:
|
|
392
|
-
|
|
393
|
-
\`\`\`ts
|
|
394
|
-
// before
|
|
395
|
-
import { bootstrap } from '@vendure/core';
|
|
396
|
-
|
|
397
|
-
// after
|
|
398
|
-
import { bootstrap } from '@vendure-platform/platform';
|
|
399
|
-
\`\`\`
|
|
400
|
-
|
|
401
|
-
If you also run a separate worker process, swap \`bootstrapWorker\` too:
|
|
402
|
-
|
|
403
|
-
\`\`\`ts
|
|
404
|
-
import { bootstrapWorker } from '@vendure-platform/platform';
|
|
405
|
-
\`\`\`
|
|
406
|
-
|
|
407
|
-
The \`@vendure-platform/platform\` bootstrap is a drop-in wrapper around
|
|
408
|
-
\`@vendure/core\`'s \`bootstrap\` that primes the runtime license guard before
|
|
409
|
-
Nest builds the DI container. Without this swap, plugins like \`OrgHierarchyPlugin\`
|
|
410
|
-
fail at startup with \`LICENSE_GUARD_NONCE_MISMATCH\`.
|
|
411
|
-
|
|
412
|
-
## 2. Imports in vendure-config.ts
|
|
413
|
-
|
|
414
|
-
Add to the top of the file (after your existing imports):
|
|
415
|
-
|
|
416
|
-
\`\`\`ts
|
|
417
|
-
${importsText}
|
|
418
|
-
\`\`\`
|
|
419
|
-
|
|
420
|
-
## 3. Plugins array
|
|
421
|
-
|
|
422
|
-
Spread \`VendurePlatform.init({...})\` into the \`plugins\` array — typically
|
|
423
|
-
between \`DefaultJobQueuePlugin\` and \`DashboardPlugin\`:
|
|
424
|
-
|
|
425
|
-
\`\`\`ts
|
|
426
|
-
...VendurePlatform.init({
|
|
427
|
-
${optionsText}
|
|
428
|
-
}),
|
|
429
|
-
\`\`\`
|
|
430
|
-
|
|
431
|
-
## 4. Order process
|
|
432
|
-
|
|
433
|
-
If \`approvalWorkflows\` is enabled (default), VendurePlatform will append
|
|
434
|
-
\`approvalOrderProcess\` to your order process chain and override
|
|
435
|
-
\`arrangingPaymentRequiresContents\` and \`checkAllItemsBeforeCancel\`. If you
|
|
436
|
-
have custom order process handlers they are preserved; the flags above are
|
|
437
|
-
not.
|
|
438
|
-
|
|
439
|
-
See https://docs.vendure.io/current/platform/getting-started/introduction for the full reference.
|
|
440
|
-
`;
|
|
441
|
-
}
|
|
442
|
-
async function runAddToExistingCli(flags) {
|
|
443
|
-
var _a;
|
|
444
|
-
const projectDir = process.cwd();
|
|
445
|
-
const detected = await detectExistingProject(projectDir);
|
|
446
|
-
if (!detected.hasVendureCore) {
|
|
447
|
-
p.log.warn('No @vendure/core dependency found in package.json. Continuing anyway — make sure this is the right directory.');
|
|
448
|
-
}
|
|
449
|
-
if (!detected.vendureConfigPath) {
|
|
450
|
-
p.log.warn('No vendure-config.ts found under src/ or server/src/. The installation guide will still be written to the project root.');
|
|
451
|
-
}
|
|
452
|
-
else {
|
|
453
|
-
p.log.info(`Detected vendure-config.ts at ${path.relative(projectDir, detected.vendureConfigPath)}`);
|
|
454
|
-
}
|
|
455
|
-
const hasIntro = flags.plugins === undefined ||
|
|
456
|
-
flags.registryToken === undefined ||
|
|
457
|
-
flags.licenseToken === undefined;
|
|
458
|
-
if (hasIntro) {
|
|
459
|
-
p.intro('Add Vendure Platform to existing project');
|
|
460
|
-
}
|
|
461
|
-
let selectedPlugins;
|
|
462
|
-
if (flags.plugins !== undefined) {
|
|
463
|
-
selectedPlugins = flags.plugins
|
|
464
|
-
.split(',')
|
|
465
|
-
.map((k) => k.trim())
|
|
466
|
-
.filter(Boolean);
|
|
467
|
-
}
|
|
468
|
-
else {
|
|
469
|
-
const pluginOptions = plugin_registry_1.pluginRegistry
|
|
470
|
-
.filter((pl) => pl.tier === 'optional' || pl.tier === 'requires-config')
|
|
471
|
-
.sort((a, b) => {
|
|
472
|
-
if (a.category !== b.category)
|
|
473
|
-
return a.category.localeCompare(b.category);
|
|
474
|
-
return a.displayName.localeCompare(b.displayName);
|
|
475
|
-
})
|
|
476
|
-
.map((pl) => ({
|
|
477
|
-
label: `${pl.displayName} (${pl.category})`,
|
|
478
|
-
value: pl.key,
|
|
479
|
-
hint: pl.tier === 'requires-config' ? 'needs configuration' : undefined,
|
|
480
|
-
}));
|
|
481
|
-
const initialValues = plugin_registry_1.pluginRegistry.filter((pl) => pl.tier === 'optional').map((pl) => pl.key);
|
|
482
|
-
const answer = await p.multiselect({
|
|
483
|
-
message: 'Optional plugins to include (core plugins are always installed):',
|
|
484
|
-
options: pluginOptions,
|
|
485
|
-
initialValues,
|
|
486
|
-
required: false,
|
|
487
|
-
});
|
|
488
|
-
if (typeof answer === 'symbol') {
|
|
489
|
-
p.cancel('Cancelled.');
|
|
490
|
-
process.exit(0);
|
|
491
|
-
}
|
|
492
|
-
selectedPlugins = answer;
|
|
493
|
-
}
|
|
494
|
-
// Two separate prompts: registry token (for .npmrc — needed by `${pm}
|
|
495
|
-
// install`) and license token (for .env — read at server boot). The
|
|
496
|
-
// Enterprise Portal issues these as two distinct values with different
|
|
497
|
-
// rotation policies, so we never collapse them.
|
|
498
|
-
const registryToken = await promptForOptionalToken(flags.registryToken, 'Vendure private-registry npm auth token (from https://enterprise.vendure.io). Used by your package manager (npm/bun/pnpm) at install time. Leave blank to skip:');
|
|
499
|
-
const licenseToken = await promptForOptionalToken(flags.licenseToken, 'Vendure Platform license token (server-side, written to .env). Leave blank to skip:');
|
|
500
|
-
return {
|
|
501
|
-
projectDir,
|
|
502
|
-
selectedPlugins,
|
|
503
|
-
dryRun: (_a = flags.dryRun) !== null && _a !== void 0 ? _a : false,
|
|
504
|
-
registryToken,
|
|
505
|
-
licenseToken,
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
/**
|
|
509
|
-
* Pre-resolve from a flag if given, otherwise interactively prompt with a
|
|
510
|
-
* masked password input. Empty / whitespace-only answers normalise to
|
|
511
|
-
* `undefined` so downstream "if a token was supplied" checks read cleanly.
|
|
512
|
-
*/
|
|
513
|
-
async function promptForOptionalToken(flagValue, message) {
|
|
514
|
-
const fromFlag = flagValue === null || flagValue === void 0 ? void 0 : flagValue.trim();
|
|
515
|
-
if (fromFlag !== undefined) {
|
|
516
|
-
return fromFlag === '' ? undefined : fromFlag;
|
|
517
|
-
}
|
|
518
|
-
const answer = await p.password({ message });
|
|
519
|
-
if (typeof answer === 'symbol') {
|
|
520
|
-
p.cancel('Cancelled.');
|
|
521
|
-
process.exit(0);
|
|
522
|
-
}
|
|
523
|
-
const trimmed = answer.trim();
|
|
524
|
-
return trimmed === '' ? undefined : trimmed;
|
|
525
|
-
}
|
|
526
|
-
/**
|
|
527
|
-
* Top-level entry point — wired up from `bin/run.ts`.
|
|
528
|
-
*/
|
|
529
|
-
async function addToExisting(options) {
|
|
530
|
-
const detected = await detectExistingProject(options.projectDir);
|
|
531
|
-
const alwaysOn = plugin_registry_1.ALWAYS_ACTIVE_KEYS.map((k) => (0, plugin_registry_1.getPlugin)(k).displayName);
|
|
532
|
-
if (alwaysOn.length > 0) {
|
|
533
|
-
p.log.info(`Always-on core plugins: ${alwaysOn.join(', ')}`);
|
|
534
|
-
}
|
|
535
|
-
const checklist = await applyAddToExisting(detected, options);
|
|
536
|
-
const numbered = formatChecklist(checklist);
|
|
537
|
-
p.note(numbered, options.dryRun ? 'Dry run — would do:' : 'Next steps');
|
|
538
|
-
p.outro(options.dryRun ? 'Dry run complete — no files written.' : 'Done.');
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
* Render the checklist as a numbered list, wrapping long entries so they fit
|
|
542
|
-
* inside clack's `note` box. clack does NOT wrap — any line wider than the
|
|
543
|
-
* terminal overflows and breaks the box border. We wrap on word boundaries to
|
|
544
|
-
* a width derived from the terminal (capped so very wide terminals don't
|
|
545
|
-
* produce unreadably long lines) and hang-indent continuation lines under the
|
|
546
|
-
* first line's text, not the list number.
|
|
547
|
-
*/
|
|
548
|
-
function formatChecklist(checklist) {
|
|
549
|
-
// clack's note draws a left bar + padding, so leave a few columns of slack.
|
|
550
|
-
const maxWidth = Math.max(40, Math.min(process.stdout.columns || 80, 100) - 6);
|
|
551
|
-
return checklist
|
|
552
|
-
.map((line, i) => {
|
|
553
|
-
const prefix = `${i + 1}. `;
|
|
554
|
-
const indent = ' '.repeat(prefix.length);
|
|
555
|
-
const wrapped = wordWrap(line, maxWidth - prefix.length);
|
|
556
|
-
return wrapped.map((seg, idx) => (idx === 0 ? prefix : indent) + seg).join('\n');
|
|
557
|
-
})
|
|
558
|
-
.join('\n');
|
|
559
|
-
}
|
|
560
|
-
/**
|
|
561
|
-
* Greedy word-wrap to `width` columns. Words longer than `width` (e.g. a long
|
|
562
|
-
* backtick code span) are left intact on their own line rather than hard-split.
|
|
563
|
-
*/
|
|
564
|
-
function wordWrap(text, width) {
|
|
565
|
-
const lines = [];
|
|
566
|
-
let current = '';
|
|
567
|
-
for (const word of text.split(/\s+/)) {
|
|
568
|
-
if (current === '') {
|
|
569
|
-
current = word;
|
|
570
|
-
}
|
|
571
|
-
else if (current.length + 1 + word.length <= width) {
|
|
572
|
-
current += ' ' + word;
|
|
573
|
-
}
|
|
574
|
-
else {
|
|
575
|
-
lines.push(current);
|
|
576
|
-
current = word;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
if (current !== '')
|
|
580
|
-
lines.push(current);
|
|
581
|
-
return lines.length > 0 ? lines : [''];
|
|
582
|
-
}
|
|
583
|
-
//# sourceMappingURL=add-to-existing.js.map
|
|
1
|
+
"use strict";var e=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var o=Object.getOwnPropertyDescriptor(t,n);o&&!("get"in o?!t.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,o)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),t=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),n=this&&this.__importStar||function(){var n=function(e){return n=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},n(e)};return function(r){if(r&&r.__esModule)return r;var o={};if(null!=r)for(var i=n(r),a=0;a<i.length;a++)"default"!==i[a]&&e(o,r,i[a]);return t(o,r),o}}();Object.defineProperty(exports,"__esModule",{value:!0}),exports.detectExistingProject=p,exports.applyAddToExisting=c,exports.runAddToExistingCli=w,exports.addToExisting=k,exports.formatChecklist=P;const r=n(require("fs-extra")),o=n(require("path")),i=n(require("@clack/prompts")),a=require("./plugin-registry"),s=require("./registry"),l=require("./template-renderer"),u="vendure-platform-installation-guide.md";async function p(e){var t,n;const i=o.join(e,"package.json");if(!await r.pathExists(i))throw new Error(`No package.json found at ${i}. Run this from your Vendure project root.`);const a=await r.readJson(i),s="@vendure/core"in{...null!==(t=a.dependencies)&&void 0!==t?t:{},...null!==(n=a.devDependencies)&&void 0!==n?n:{}},l=[o.join(e,"src","vendure-config.ts"),o.join(e,"server","src","vendure-config.ts"),o.join(e,"src","vendure-config.js")];let u=null;for(const e of l)if(await r.pathExists(e)){u=e;break}return{projectDir:e,packageJsonPath:i,vendureConfigPath:u,hasVendureCore:s,envPath:o.join(e,".env"),npmrcPath:o.join(e,".npmrc"),gitignorePath:o.join(e,".gitignore")}}async function c(e,t){const{selectedPlugins:n,dryRun:i,registryToken:s,licenseToken:p}=t,c=(0,a.resolveActivePluginKeys)(n),w=c.map(e=>(0,a.getPlugin)(e)),b=(0,l.resolvePluginVersionSpec)(),k=[],P=w.map(e=>e.packageName),j=await d(e.packageJsonPath,b,P,i);if(j.length>0){const e=1===j.length?j[0]:`${j.length} packages (${j[0]}, \u2026)`;k.push(`Added ${e} at ${b} to package.json \u2014 run \`npm install\` (or your package manager equivalent).`)}const E=f(w,p),_=await m(e.envPath,E,i);_>0&&k.push(`Appended ${_} env var(s) to .env \u2014 fill in real values before booting.`),p&&await g(e.envPath,p,i)&&k.push("Filled in the empty VENDURE_PLATFORM_LICENSE_TOKEN value in .env.");const A=await h(e.npmrcPath,s,i);if(A.scopeAdded||A.authAdded){const e=[];A.scopeAdded&&e.push("scope"),A.authAdded&&e.push("auth token"),k.push(`Updated .npmrc (${e.join(" + ")}).`)}await v(e.gitignorePath,".npmrc",i)&&k.push("Added .npmrc to .gitignore so any future registry token never gets committed.");const N=y(w,c),O=o.join(e.projectDir,u);return i||await r.writeFile(O,N),k.push(`Wrote ${o.relative(e.projectDir,O)} \u2014 follow it to wire up your vendure-config.ts.`),k.push("Swap `import { bootstrap } from '@vendure/core'` for `'@vendure-platform/platform'` in your server entry file (and `bootstrapWorker` if you have a worker). See the installation guide's \"Bootstrap import\" section."),k.push("Generate and run a migration for the new platform entities."),k.push("Rebuild the dashboard if you serve a pre-built artefact."),k.push("Grant new permissions to existing admin roles via Settings \u2192 Roles."),k}async function d(e,t,n,o){var i;const a=await r.readJson(e);null!==(i=a.dependencies)&&void 0!==i||(a.dependencies={});const s=["@vendure-platform/platform",...n].filter((e,t,n)=>n.indexOf(e)===t),l=[];for(const e of s)a.dependencies[e]||(a.dependencies[e]=t,l.push(e));return l.length>0&&!o&&await r.writeJson(e,a,{spaces:2}),l}function f(e,t){const n=[{name:"VENDURE_PLATFORM_LICENSE_TOKEN",defaultValue:null!=t?t:""},{name:"VENDURE_PLATFORM_LICENSE_GUARD_LOCAL_DEV",defaultValue:"1"}];for(const t of e)for(const e of t.envVars)n.some(t=>t.name===e.name)||n.push(e);return n}async function g(e,t,n){if(!await r.pathExists(e))return!1;const o=(await r.readFile(e,"utf8")).split("\n");let i=!1;const a="VENDURE_PLATFORM_LICENSE_TOKEN";for(let e=0;e<o.length;e++){const n=o[e].trim();if(!n.startsWith("#")&&n===`${a}=`){o[e]=`${a}=${t}`,i=!0;break}}return i&&!n&&await r.writeFile(e,o.join("\n")),i}async function m(e,t,n){let o="";await r.pathExists(e)&&(o=await r.readFile(e,"utf8"));const i=new Set(o.split("\n").map(e=>{var t;return null===(t=e.split("=")[0])||void 0===t?void 0:t.trim()}).filter(e=>Boolean(e)&&!e.startsWith("#"))),a=t.filter(e=>!i.has(e.name));if(0===a.length)return 0;const s=a.map(e=>`${e.name}=${e.defaultValue}`).join("\n")+"\n";if(!n){const t=o.endsWith("\n")||""===o?"":"\n";await r.writeFile(e,o+t+"\n# Added by @vendure-platform/create add\n"+s)}return a.length}async function h(e,t,n){const o=`@vendure-platform:registry=${(0,s.getRegistryUrl)()}`,i=`//${(0,s.getRegistryHostname)()}/:_authToken=`;let a="";await r.pathExists(e)&&(a=await r.readFile(e,"utf8"));const l=a.includes("@vendure-platform:registry="),u=a.includes(i),p=[];if(l||p.push(o),t&&!u&&p.push(`${i}${t}`),0===p.length)return{scopeAdded:!1,authAdded:!1};const c=""===a||a.endsWith("\n")?"":"\n";return n||await r.writeFile(e,a+c+p.join("\n")+"\n"),{scopeAdded:!l,authAdded:Boolean(t)&&!u}}async function v(e,t,n){let o="";await r.pathExists(e)&&(o=await r.readFile(e,"utf8"));const i=o.split("\n").map(e=>e.trim());if(i.includes(t)||i.includes(`/${t}`))return!1;const a=""===o||o.endsWith("\n")?"":"\n";return n||await r.writeFile(e,o+a+t+"\n"),!0}function y(e,t){const n=["import { VendurePlatform } from '@vendure-platform/platform';"],r=[];for(const t of e)t.platformImports&&n.push(...t.platformImports),t.platformOptionsBlock&&r.push(` ${t.platformOptionsBlock},`);const o=a.pluginRegistry.filter(e=>"optional"===e.tier&&!t.includes(e.key)).map(e=>e.key);for(const e of o){const t=(0,a.getPlugin)(e).platformKey;r.push(` ${t}: false,`)}return`# Vendure Platform installation guide\n\nPaste these changes into your existing project. Step 1 is the most important \u2014\nwithout it, every Vendure Platform plugin refuses to start with\n\`LICENSE_GUARD_NONCE_MISMATCH\`.\n\n## 1. Bootstrap import (server entry point)\n\nIn your server entry file (typically \`src/index.ts\` or wherever you call\n\`bootstrap()\`), swap the bootstrap import from \`@vendure/core\` to\n\`@vendure-platform/platform\`:\n\n\`\`\`ts\n// before\nimport { bootstrap } from '@vendure/core';\n\n// after\nimport { bootstrap } from '@vendure-platform/platform';\n\`\`\`\n\nIf you also run a separate worker process, swap \`bootstrapWorker\` too:\n\n\`\`\`ts\nimport { bootstrapWorker } from '@vendure-platform/platform';\n\`\`\`\n\nThe \`@vendure-platform/platform\` bootstrap is a drop-in wrapper around\n\`@vendure/core\`'s \`bootstrap\` that primes the runtime license guard before\nNest builds the DI container. Without this swap, plugins like \`OrgHierarchyPlugin\`\nfail at startup with \`LICENSE_GUARD_NONCE_MISMATCH\`.\n\n## 2. Imports in vendure-config.ts\n\nAdd to the top of the file (after your existing imports):\n\n\`\`\`ts\n${n.join("\n")}\n\`\`\`\n\n## 3. Plugins array\n\nSpread \`VendurePlatform.init({...})\` into the \`plugins\` array \u2014 typically\nbetween \`DefaultJobQueuePlugin\` and \`DashboardPlugin\`:\n\n\`\`\`ts\n...VendurePlatform.init({\n${0===r.length?" // All optional plugins enabled with default config":r.join("\n")}\n}),\n\`\`\`\n\n## 4. Order process\n\nIf \`approvalWorkflows\` is enabled (default), VendurePlatform will append\n\`approvalOrderProcess\` to your order process chain and override\n\`arrangingPaymentRequiresContents\` and \`checkAllItemsBeforeCancel\`. If you\nhave custom order process handlers they are preserved; the flags above are\nnot.\n\nSee https://docs.vendure.io/current/platform/getting-started/introduction for the full reference.\n`}async function w(e){var t;const n=process.cwd(),r=await p(n);let s;if(r.hasVendureCore||i.log.warn("No @vendure/core dependency found in package.json. Continuing anyway \u2014 make sure this is the right directory."),r.vendureConfigPath?i.log.info(`Detected vendure-config.ts at ${o.relative(n,r.vendureConfigPath)}`):i.log.warn("No vendure-config.ts found under src/ or server/src/. The installation guide will still be written to the project root."),(void 0===e.plugins||void 0===e.registryToken||void 0===e.licenseToken)&&i.intro("Add Vendure Platform to existing project"),void 0!==e.plugins)s=e.plugins.split(",").map(e=>e.trim()).filter(Boolean);else{const e=a.pluginRegistry.filter(e=>"optional"===e.tier||"requires-config"===e.tier).sort((e,t)=>e.category!==t.category?e.category.localeCompare(t.category):e.displayName.localeCompare(t.displayName)).map(e=>({label:`${e.displayName} (${e.category})`,value:e.key,hint:"requires-config"===e.tier?"needs configuration":void 0})),t=a.pluginRegistry.filter(e=>"optional"===e.tier).map(e=>e.key),n=await i.multiselect({message:"Optional plugins to include (core plugins are always installed):",options:e,initialValues:t,required:!1});"symbol"==typeof n&&(i.cancel("Cancelled."),process.exit(0)),s=n}const l=await b(e.registryToken,"Vendure private-registry npm auth token (from https://enterprise.vendure.io). Used by your package manager (npm/bun/pnpm) at install time. Leave blank to skip:"),u=await b(e.licenseToken,"Vendure Platform license token (server-side, written to .env). Leave blank to skip:");return{projectDir:n,selectedPlugins:s,dryRun:null!==(t=e.dryRun)&&void 0!==t&&t,registryToken:l,licenseToken:u}}async function b(e,t){const n=null==e?void 0:e.trim();if(void 0!==n)return""===n?void 0:n;const r=await i.password({message:t});"symbol"==typeof r&&(i.cancel("Cancelled."),process.exit(0));const o=r.trim();return""===o?void 0:o}async function k(e){const t=await p(e.projectDir),n=a.ALWAYS_ACTIVE_KEYS.map(e=>(0,a.getPlugin)(e).displayName);n.length>0&&i.log.info(`Always-on core plugins: ${n.join(", ")}`);const r=P(await c(t,e));i.note(r,e.dryRun?"Dry run \u2014 would do:":"Next steps"),i.outro(e.dryRun?"Dry run complete \u2014 no files written.":"Done.")}function P(e){const t=Math.max(40,Math.min(process.stdout.columns||80,100)-6);return e.map((e,n)=>{const r=`${n+1}. `,o=" ".repeat(r.length);return j(e,t-r.length).map((e,t)=>(0===t?r:o)+e).join("\n")}).join("\n")}function j(e,t){const n=[];let r="";for(const o of e.split(/\s+/))""===r?r=o:r.length+1+o.length<=t?r+=" "+o:(n.push(r),r=o);return""!==r&&n.push(r),n.length>0?n:[""]}
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"greeting": "Hallo, {name}",
|
|
20
20
|
"catalog": "Katalog",
|
|
21
21
|
"quotes": "Angebote",
|
|
22
|
+
"sharedCarts": "Geteilte Warenkörbe",
|
|
22
23
|
"company": "Unternehmen",
|
|
23
24
|
"businessUnit": "Geschäftseinheit",
|
|
24
25
|
"shoppingCart": "Warenkorb",
|
|
@@ -565,6 +566,7 @@
|
|
|
565
566
|
"orders": "Bestellungen",
|
|
566
567
|
"storeCredits": "Guthaben",
|
|
567
568
|
"quotes": "Angebote",
|
|
569
|
+
"sharedCarts": "Geteilte Warenkörbe",
|
|
568
570
|
"shoppingLists": "Einkaufslisten",
|
|
569
571
|
"quickOrder": "Schnellbestellung",
|
|
570
572
|
"approvals": "Genehmigungen",
|