@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.
Files changed (59) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +7 -7
  3. package/dist/add-to-existing.js +1 -583
  4. package/dist/assets/storefront/messages/de.json +2 -0
  5. package/dist/assets/storefront/messages/en.json +2 -0
  6. package/dist/assets/storefront/package.json +1 -1
  7. package/dist/assets/storefront/src/app/[locale]/(catalog)/product/[slug]/page.tsx +7 -2
  8. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/activity-feed.tsx +152 -0
  9. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/add-item-search.tsx +130 -0
  10. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/add-member-form.tsx +124 -0
  11. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/members-panel.tsx +240 -0
  12. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/page.tsx +47 -0
  13. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/rename-dialog.tsx +96 -0
  14. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/[id]/shared-cart-detail-client.tsx +555 -0
  15. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/actions.ts +260 -0
  16. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/new/new-shared-cart-form.tsx +77 -0
  17. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/new/page.tsx +47 -0
  18. package/dist/assets/storefront/src/app/[locale]/account/shared-carts/page.tsx +263 -0
  19. package/dist/assets/storefront/src/app/[locale]/cart/cart.tsx +12 -1
  20. package/dist/assets/storefront/src/app/[locale]/cart/order-summary.tsx +23 -0
  21. package/dist/assets/storefront/src/components/commerce/account-nav-items.ts +2 -0
  22. package/dist/assets/storefront/src/components/commerce/add-to-shared-cart.tsx +225 -0
  23. package/dist/assets/storefront/src/components/commerce/product-info.tsx +14 -1
  24. package/dist/assets/storefront/src/components/commerce/shared-cart-role.ts +39 -0
  25. package/dist/assets/storefront/src/components/commerce/shared-cart-status-badge.tsx +24 -0
  26. package/dist/assets/storefront/src/graphql-env.d.ts +28 -15
  27. package/dist/assets/storefront/src/lib/vendure/api.ts +8 -4
  28. package/dist/assets/storefront/src/lib/vendure/mutations.ts +96 -0
  29. package/dist/assets/storefront/src/lib/vendure/queries.ts +142 -0
  30. package/dist/assets/storefront/src/schema.graphql +321 -61
  31. package/dist/bin/run.js +1 -119
  32. package/dist/cli.js +1 -309
  33. package/dist/git-init.js +1 -60
  34. package/dist/index.js +1 -19
  35. package/dist/plugin-registry.js +1 -203
  36. package/dist/registry.js +1 -29
  37. package/dist/scaffold-shared.js +1 -124
  38. package/dist/scaffold-storefront-only.js +1 -101
  39. package/dist/scaffolder.js +1 -203
  40. package/dist/sort-package-json.js +1 -26
  41. package/dist/storefront-copier.js +1 -149
  42. package/dist/template-renderer.js +1 -221
  43. package/dist/types.js +1 -3
  44. package/package.json +5 -4
  45. package/dist/add-to-existing.js.map +0 -1
  46. package/dist/assets/storefront/src/lib/quantity.test.js +0 -20
  47. package/dist/bin/run.js.map +0 -1
  48. package/dist/cli.js.map +0 -1
  49. package/dist/git-init.js.map +0 -1
  50. package/dist/index.js.map +0 -1
  51. package/dist/plugin-registry.js.map +0 -1
  52. package/dist/registry.js.map +0 -1
  53. package/dist/scaffold-shared.js.map +0 -1
  54. package/dist/scaffold-storefront-only.js.map +0 -1
  55. package/dist/scaffolder.js.map +0 -1
  56. package/dist/sort-package-json.js.map +0 -1
  57. package/dist/storefront-copier.js.map +0 -1
  58. package/dist/template-renderer.js.map +0 -1
  59. 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 — keep them straight:
39
+ The Vendure Enterprise Portal issues **two distinct tokens** with different purposes - keep them straight:
40
40
 
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`.
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** — 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.
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 — 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.
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
 
@@ -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",