@vendure/cloud-config 0.0.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/README.md +298 -0
- package/dist/cloud-config.d.ts +55 -0
- package/dist/cloud-config.d.ts.map +1 -0
- package/dist/cloud-config.js +2 -0
- package/dist/cloud-config.js.map +1 -0
- package/dist/cloud-dashboard-plugin.d.ts +28 -0
- package/dist/cloud-dashboard-plugin.d.ts.map +1 -0
- package/dist/cloud-dashboard-plugin.js +91 -0
- package/dist/cloud-dashboard-plugin.js.map +1 -0
- package/dist/cloud-plugin-declaration.d.ts +12 -0
- package/dist/cloud-plugin-declaration.d.ts.map +1 -0
- package/dist/cloud-plugin-declaration.js +53 -0
- package/dist/cloud-plugin-declaration.js.map +1 -0
- package/dist/composition.d.ts +23 -0
- package/dist/composition.d.ts.map +1 -0
- package/dist/composition.js +147 -0
- package/dist/composition.js.map +1 -0
- package/dist/define-cloud-config.d.ts +19 -0
- package/dist/define-cloud-config.d.ts.map +1 -0
- package/dist/define-cloud-config.js +47 -0
- package/dist/define-cloud-config.js.map +1 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations.d.ts +32 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +250 -0
- package/dist/migrations.js.map +1 -0
- package/dist/outbound-hosts.d.ts +16 -0
- package/dist/outbound-hosts.d.ts.map +1 -0
- package/dist/outbound-hosts.js +211 -0
- package/dist/outbound-hosts.js.map +1 -0
- package/dist/path.d.ts +2 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +18 -0
- package/dist/path.js.map +1 -0
- package/dist/platform-fields.d.ts +71 -0
- package/dist/platform-fields.d.ts.map +1 -0
- package/dist/platform-fields.js +94 -0
- package/dist/platform-fields.js.map +1 -0
- package/dist/plugin-attribution.d.ts +27 -0
- package/dist/plugin-attribution.d.ts.map +1 -0
- package/dist/plugin-attribution.js +97 -0
- package/dist/plugin-attribution.js.map +1 -0
- package/dist/runtime-backstop.d.ts +8 -0
- package/dist/runtime-backstop.d.ts.map +1 -0
- package/dist/runtime-backstop.js +20 -0
- package/dist/runtime-backstop.js.map +1 -0
- package/dist/secrets.d.ts +14 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +109 -0
- package/dist/secrets.js.map +1 -0
- package/dist/stack.d.ts +3 -0
- package/dist/stack.d.ts.map +1 -0
- package/dist/stack.js +58 -0
- package/dist/stack.js.map +1 -0
- package/dist/superseded-plugins.d.ts +19 -0
- package/dist/superseded-plugins.d.ts.map +1 -0
- package/dist/superseded-plugins.js +41 -0
- package/dist/superseded-plugins.js.map +1 -0
- package/dist/vendure-extension.d.ts +38 -0
- package/dist/vendure-extension.d.ts.map +1 -0
- package/dist/vendure-extension.js +111 -0
- package/dist/vendure-extension.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { VendureExtension } from "./vendure-extension.js";
|
|
2
|
+
export interface UndeclaredHostReport {
|
|
3
|
+
readonly host: string;
|
|
4
|
+
readonly extensionId: string | undefined;
|
|
5
|
+
readonly declaredHosts: readonly string[];
|
|
6
|
+
readonly message: string;
|
|
7
|
+
}
|
|
8
|
+
export type UndeclaredHostReporter = (report: UndeclaredHostReport) => void;
|
|
9
|
+
export interface OutboundHostCheckOptions {
|
|
10
|
+
readonly extensions: readonly VendureExtension[];
|
|
11
|
+
readonly report?: UndeclaredHostReporter;
|
|
12
|
+
}
|
|
13
|
+
type Uninstall = () => void;
|
|
14
|
+
export declare function installOutboundHostCheck(options: OutboundHostCheckOptions): Uninstall;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=outbound-hosts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-hosts.d.ts","sourceRoot":"","sources":["../src/outbound-hosts.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAa/D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,sBAAsB,GAAG,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;AAE5E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,UAAU,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAGjD,QAAQ,CAAC,MAAM,CAAC,EAAE,sBAAsB,CAAC;CAC1C;AAmKD,KAAK,SAAS,GAAG,MAAM,IAAI,CAAC;AAQ5B,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,wBAAwB,GAAG,SAAS,CAwErF"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { dirname, sep } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { stackFrameFiles } from "./stack.js";
|
|
5
|
+
// A hostname as declared and as dialled, compared the way DNS does: case-insensitively, and
|
|
6
|
+
// ignoring the trailing dot of a fully qualified name. Matching is exact — there is no
|
|
7
|
+
// wildcard and no implied subdomain, because "declared api.acme.com" allowing
|
|
8
|
+
// "evil.api.acme.com" would be a surprise in the direction that matters.
|
|
9
|
+
function normalizeHost(host) {
|
|
10
|
+
return host.trim().toLowerCase().replace(/\.$/, "");
|
|
11
|
+
}
|
|
12
|
+
// How far down the stack to look for an extension. A plugin calling out through a client
|
|
13
|
+
// library sits under however many frames that library adds, and 30 covers the ones measured
|
|
14
|
+
// here with room to spare; past that the call is left unattributed rather than searched for
|
|
15
|
+
// indefinitely, because reading a deep stack is the expensive part of this check.
|
|
16
|
+
const ATTRIBUTION_FRAME_LIMIT = 30;
|
|
17
|
+
// This file's own directory, so its frames can be skipped when reading the stack.
|
|
18
|
+
const selfDirectory = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
// Which extension made the call, read from the stack. Same technique as
|
|
20
|
+
// `defineVendureExtension`'s declaring-file trap and for the same reason: our own
|
|
21
|
+
// `prepareStackTrace` is installed so that `--enable-source-maps` cannot rewrite the frames
|
|
22
|
+
// back to `.ts` paths the image does not ship.
|
|
23
|
+
function attribute(state, boundary) {
|
|
24
|
+
for (const path of stackFrameFiles(boundary, ATTRIBUTION_FRAME_LIMIT)) {
|
|
25
|
+
if (path === undefined || path.startsWith(selfDirectory))
|
|
26
|
+
continue;
|
|
27
|
+
const match = state.attributions.find((candidate) => path === candidate.directory || path.startsWith(candidate.directory + sep));
|
|
28
|
+
if (match)
|
|
29
|
+
return match.extension;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
// The message ADR-0028 specifies, verbatim in shape:
|
|
34
|
+
//
|
|
35
|
+
// Extension acme.erp attempted outbound access to api.other-erp.example.
|
|
36
|
+
// Declared outbound hosts: erp.acme.com
|
|
37
|
+
function formatReport(host, extension) {
|
|
38
|
+
const declaredHosts = extension ? [...extension.outboundHosts] : [];
|
|
39
|
+
const subject = extension ? `Extension ${extension.id}` : "An extension";
|
|
40
|
+
const declared = declaredHosts.length > 0
|
|
41
|
+
? `Declared outbound hosts: ${declaredHosts.join(", ")}`
|
|
42
|
+
: "It declares no outbound hosts.";
|
|
43
|
+
return {
|
|
44
|
+
host,
|
|
45
|
+
extensionId: extension?.id,
|
|
46
|
+
declaredHosts,
|
|
47
|
+
message: `Vendure Cloud: ${subject} attempted outbound access to ${host}.\n${declared}\n This is reported, not blocked. Add the host to the extension's outboundHosts to silence it.`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function check(state, rawHost) {
|
|
51
|
+
if (rawHost === undefined || rawHost === "")
|
|
52
|
+
return;
|
|
53
|
+
const host = normalizeHost(rawHost);
|
|
54
|
+
// The fast path, and the reason an allowed call costs one Set lookup rather than a captured
|
|
55
|
+
// stack. Its cost is that an extension reaching a host another extension declared is not
|
|
56
|
+
// reported. That is accepted: this is a hygiene control, and one acceptance criterion on
|
|
57
|
+
// CLO-412 is that an allowed call carries no measurable per-request cost. Attributing every
|
|
58
|
+
// call would mean capturing a stack on every request to satisfy a control that a single
|
|
59
|
+
// line of code can bypass anyway.
|
|
60
|
+
if (state.declaredAnywhere.has(host))
|
|
61
|
+
return;
|
|
62
|
+
const extension = attribute(state, check);
|
|
63
|
+
// Nothing on the stack belongs to an extension, so there is no declaration this call is
|
|
64
|
+
// measured against. Vendure core's own traffic, the database driver's, and a library called
|
|
65
|
+
// from platform code all land here, and reporting them would drown the signal.
|
|
66
|
+
if (extension === undefined)
|
|
67
|
+
return;
|
|
68
|
+
// The extension declared nothing, so it opted out of the check. CLO-412 records the
|
|
69
|
+
// reasoning: reading "declared nothing" as "may reach nothing" would report against every
|
|
70
|
+
// extension in existence today, and a report that fires on everything is not read.
|
|
71
|
+
if (extension.outboundHosts.length === 0)
|
|
72
|
+
return;
|
|
73
|
+
const seen = `${extension.id}\u0000${host}`;
|
|
74
|
+
if (state.reported.has(seen))
|
|
75
|
+
return;
|
|
76
|
+
state.reported.add(seen);
|
|
77
|
+
state.report(formatReport(host, extension));
|
|
78
|
+
}
|
|
79
|
+
function hostFromUrl(value) {
|
|
80
|
+
try {
|
|
81
|
+
return new URL(value).hostname;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// `fetch` takes a string, a URL, or a Request. Reading `.url` off the third rather than
|
|
88
|
+
// naming `Request`, because the DOM lib is not in this package's types and the shape is the
|
|
89
|
+
// only part that matters.
|
|
90
|
+
function hostFromFetchInput(input) {
|
|
91
|
+
if (typeof input === "string")
|
|
92
|
+
return hostFromUrl(input);
|
|
93
|
+
if (input instanceof URL)
|
|
94
|
+
return input.hostname;
|
|
95
|
+
if (typeof input === "object" && input !== null) {
|
|
96
|
+
const { url } = input;
|
|
97
|
+
if (typeof url === "string")
|
|
98
|
+
return hostFromUrl(url);
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
function hostFromRequestArguments(args, depth = 0) {
|
|
103
|
+
for (const argument of args) {
|
|
104
|
+
// `Socket.prototype.connect` is reached with Node's own normalised argument list, which is
|
|
105
|
+
// an array holding the options object and the callback, so the options are one level down
|
|
106
|
+
// rather than in the position a direct caller would put them.
|
|
107
|
+
//
|
|
108
|
+
// Bounded at the single level Node actually produces, because this runs on the caller's
|
|
109
|
+
// arguments before Node has validated them. Anything deeper is a caller passing something
|
|
110
|
+
// strange, and a self-referencing array would otherwise exhaust the stack inside a check
|
|
111
|
+
// whose whole job is to watch without getting in the way.
|
|
112
|
+
if (Array.isArray(argument)) {
|
|
113
|
+
if (depth >= 1)
|
|
114
|
+
continue;
|
|
115
|
+
const nested = hostFromRequestArguments(argument, depth + 1);
|
|
116
|
+
if (nested !== undefined)
|
|
117
|
+
return nested;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (typeof argument === "string") {
|
|
121
|
+
const fromUrl = hostFromUrl(argument);
|
|
122
|
+
if (fromUrl !== undefined)
|
|
123
|
+
return fromUrl;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (argument instanceof URL)
|
|
127
|
+
return argument.hostname;
|
|
128
|
+
if (typeof argument === "object" && argument !== null) {
|
|
129
|
+
const { hostname, host } = argument;
|
|
130
|
+
if (typeof hostname === "string")
|
|
131
|
+
return hostname;
|
|
132
|
+
// `host` may carry a port; the declaration is of hosts, so the port is dropped.
|
|
133
|
+
if (typeof host === "string")
|
|
134
|
+
return host.split(":")[0];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
// Installed by the platform entrypoint, and by `vendure dev`, so the check behaves the same
|
|
140
|
+
// in both. Returns the function that undoes it, which is what the tests use and what an
|
|
141
|
+
// entrypoint would call on shutdown.
|
|
142
|
+
//
|
|
143
|
+
// Nothing is patched at all when no extension declares a host, so an application that has not
|
|
144
|
+
// adopted the field pays nothing and cannot be affected by a bug in here.
|
|
145
|
+
export function installOutboundHostCheck(options) {
|
|
146
|
+
const declaring = options.extensions.filter((extension) => extension.outboundHosts.length > 0);
|
|
147
|
+
if (declaring.length === 0)
|
|
148
|
+
return () => undefined;
|
|
149
|
+
const declaredAnywhere = new Set();
|
|
150
|
+
for (const extension of declaring) {
|
|
151
|
+
for (const host of extension.outboundHosts)
|
|
152
|
+
declaredAnywhere.add(normalizeHost(host));
|
|
153
|
+
}
|
|
154
|
+
const attributions = options.extensions
|
|
155
|
+
.flatMap((extension) => {
|
|
156
|
+
if (extension.declaredIn === undefined)
|
|
157
|
+
return [];
|
|
158
|
+
return [{ directory: dirname(extension.declaredIn), extension }];
|
|
159
|
+
})
|
|
160
|
+
.sort((left, right) => right.directory.length - left.directory.length);
|
|
161
|
+
const state = {
|
|
162
|
+
declaredAnywhere,
|
|
163
|
+
attributions,
|
|
164
|
+
report: options.report ?? ((report) => process.stderr.write(`${report.message}\n`)),
|
|
165
|
+
reported: new Set(),
|
|
166
|
+
};
|
|
167
|
+
const undo = [];
|
|
168
|
+
const originalFetch = globalThis.fetch;
|
|
169
|
+
if (typeof originalFetch === "function") {
|
|
170
|
+
globalThis.fetch = function patchedFetch(input, init) {
|
|
171
|
+
check(state, hostFromFetchInput(input));
|
|
172
|
+
return originalFetch.call(this, input, init);
|
|
173
|
+
};
|
|
174
|
+
undo.push(() => {
|
|
175
|
+
globalThis.fetch = originalFetch;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
// Everything that is not `fetch` is caught one level lower, at the socket, because that is
|
|
179
|
+
// the only interception point that behaves the same under both module systems — which is an
|
|
180
|
+
// acceptance criterion on CLO-412 rather than a preference.
|
|
181
|
+
//
|
|
182
|
+
// Replacing `net.connect` and `http.request` on the module object does not work. An ES
|
|
183
|
+
// module's named import is a snapshot of the binding taken when the module was linked, so
|
|
184
|
+
// `import { connect } from "node:net"` keeps calling the original however the module object
|
|
185
|
+
// is rewritten afterwards, while a CommonJS caller doing `require("node:net").connect` sees
|
|
186
|
+
// the replacement. That is the same control behaving differently in the two module systems,
|
|
187
|
+
// and it silently covers only half of them.
|
|
188
|
+
//
|
|
189
|
+
// `net.Socket.prototype.connect` has no such split. `net.connect`, `net.createConnection`,
|
|
190
|
+
// `http.request`, `https.request` and the global `fetch` all end at a Socket, and the method
|
|
191
|
+
// is looked up on the prototype at call time whoever reached it.
|
|
192
|
+
const require = createRequire(import.meta.url);
|
|
193
|
+
const net = require("node:net");
|
|
194
|
+
const socketPrototype = net.Socket.prototype;
|
|
195
|
+
const originalConnect = socketPrototype.connect;
|
|
196
|
+
if (typeof originalConnect === "function") {
|
|
197
|
+
socketPrototype.connect = function patchedConnect(...args) {
|
|
198
|
+
check(state, hostFromRequestArguments(args));
|
|
199
|
+
return originalConnect.apply(this, args);
|
|
200
|
+
};
|
|
201
|
+
undo.push(() => {
|
|
202
|
+
socketPrototype.connect = originalConnect;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return () => {
|
|
206
|
+
for (const step of undo)
|
|
207
|
+
step();
|
|
208
|
+
undo.length = 0;
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=outbound-hosts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-hosts.js","sourceRoot":"","sources":["../src/outbound-hosts.ts"],"names":[],"mappings":"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"}
|
package/dist/path.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAQA,wBAAgB,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAO/D"}
|
package/dist/path.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Walks a dot-separated path over an unknown value, returning undefined at anything that is
|
|
2
|
+
// not a traversable object rather than throwing.
|
|
3
|
+
//
|
|
4
|
+
// Every check over the platform-owned fields reads through this one function — the runtime
|
|
5
|
+
// backstop, the forward assertion and the attribution diff. They must agree on what "this
|
|
6
|
+
// field is set" means: a second implementation that treated a null option object as a miss,
|
|
7
|
+
// or that stopped at a prototype property, would let one check pass a config another
|
|
8
|
+
// rejects, and the boot error would name a field the customer's file does not set.
|
|
9
|
+
export function readPath(source, path) {
|
|
10
|
+
let current = source;
|
|
11
|
+
for (const segment of path.split(".")) {
|
|
12
|
+
if (typeof current !== "object" || current === null)
|
|
13
|
+
return undefined;
|
|
14
|
+
current = current[segment];
|
|
15
|
+
}
|
|
16
|
+
return current;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=path.js.map
|
package/dist/path.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.js","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,iDAAiD;AACjD,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,4FAA4F;AAC5F,qFAAqF;AACrF,mFAAmF;AACnF,MAAM,UAAU,QAAQ,CAAC,MAAe,EAAE,IAAY;IACpD,IAAI,OAAO,GAAG,MAAM,CAAC;IACrB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC;QACtE,OAAO,GAAI,OAAmC,CAAC,OAAO,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export interface PlatformOwnedField {
|
|
2
|
+
path: string;
|
|
3
|
+
reason: string;
|
|
4
|
+
writtenBy?: {
|
|
5
|
+
plugin: string;
|
|
6
|
+
replacement: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
declare const FIELD_SPECS: readonly [{
|
|
10
|
+
readonly path: "dbConnectionOptions";
|
|
11
|
+
readonly reason: "The database connection is supplied by Vendure Cloud, including credential rotation. Remove dbConnectionOptions from your config.";
|
|
12
|
+
}, {
|
|
13
|
+
readonly path: "logger";
|
|
14
|
+
readonly reason: "Logging is supplied by Vendure Cloud so output reaches the platform log pipeline from the server, the worker and migrations alike. To forward logs elsewhere, use a log drain rather than replacing the logger.";
|
|
15
|
+
}, {
|
|
16
|
+
readonly path: "apiOptions.port";
|
|
17
|
+
readonly reason: "The port is supplied by Vendure Cloud and must match what the load balancer routes to. Remove apiOptions.port.";
|
|
18
|
+
}, {
|
|
19
|
+
readonly path: "apiOptions.hostname";
|
|
20
|
+
readonly reason: "The hostname is supplied by Vendure Cloud. Remove apiOptions.hostname.";
|
|
21
|
+
}, {
|
|
22
|
+
readonly path: "authOptions.superadminCredentials";
|
|
23
|
+
readonly reason: "Vendure Cloud generates the superadmin credential for each environment and surfaces it once. Remove authOptions.superadminCredentials.";
|
|
24
|
+
}, {
|
|
25
|
+
readonly path: "authOptions.sessionCacheStrategy";
|
|
26
|
+
readonly reason: "The session cache is backed by platform-managed infrastructure. Remove authOptions.sessionCacheStrategy.";
|
|
27
|
+
}, {
|
|
28
|
+
readonly path: "authOptions.sessionCacheTTL";
|
|
29
|
+
readonly reason: "The session cache TTL is the dominant lever on platform cache cost, so it is a platform decision. Remove authOptions.sessionCacheTTL.";
|
|
30
|
+
}, {
|
|
31
|
+
readonly path: "systemOptions.cacheStrategy";
|
|
32
|
+
readonly reason: "The cache is supplied by Vendure Cloud. Remove systemOptions.cacheStrategy, and remove RedisCachePlugin from your plugins array.";
|
|
33
|
+
readonly writtenBy: {
|
|
34
|
+
readonly plugin: "RedisCachePlugin";
|
|
35
|
+
readonly replacement: "the platform cache strategy, which is injected automatically";
|
|
36
|
+
};
|
|
37
|
+
}, {
|
|
38
|
+
readonly path: "systemOptions.healthChecks";
|
|
39
|
+
readonly reason: "The health check is shallow by design: it must not touch the database, because a target group that marks every server unhealthy during a database blip causes ECS to replace all of them at once. Remove systemOptions.healthChecks.";
|
|
40
|
+
}, {
|
|
41
|
+
readonly path: "assetOptions.assetStorageStrategy";
|
|
42
|
+
readonly reason: "Asset storage is supplied by Vendure Cloud. Remove assetOptions.assetStorageStrategy, and use CloudAssetServerPlugin in place of AssetServerPlugin.";
|
|
43
|
+
readonly writtenBy: {
|
|
44
|
+
readonly plugin: "AssetServerPlugin";
|
|
45
|
+
readonly replacement: "CloudAssetServerPlugin";
|
|
46
|
+
};
|
|
47
|
+
}, {
|
|
48
|
+
readonly path: "jobQueueOptions.jobQueueStrategy";
|
|
49
|
+
readonly reason: "The job queue is supplied by Vendure Cloud. Remove jobQueueOptions.jobQueueStrategy, and remove BullMQJobQueuePlugin from your plugins array.";
|
|
50
|
+
readonly writtenBy: {
|
|
51
|
+
readonly plugin: "BullMQJobQueuePlugin";
|
|
52
|
+
readonly replacement: "the platform job queue strategy, which is injected automatically";
|
|
53
|
+
};
|
|
54
|
+
}, {
|
|
55
|
+
readonly path: "schedulerOptions.schedulerStrategy";
|
|
56
|
+
readonly reason: "Scheduled tasks are driven by Vendure Cloud, because a worker scaled to zero runs none. Remove schedulerOptions.schedulerStrategy, and remove DefaultSchedulerPlugin from your plugins array.";
|
|
57
|
+
readonly writtenBy: {
|
|
58
|
+
readonly plugin: "DefaultSchedulerPlugin";
|
|
59
|
+
readonly replacement: "the platform scheduler strategy, which is injected automatically";
|
|
60
|
+
};
|
|
61
|
+
}, {
|
|
62
|
+
readonly path: "schedulerOptions.runTasksInWorkerOnly";
|
|
63
|
+
readonly reason: "Vendure Cloud pins runTasksInWorkerOnly to false so the server ticks when the worker is asleep. Remove schedulerOptions.runTasksInWorkerOnly.";
|
|
64
|
+
}];
|
|
65
|
+
export declare const PLATFORM_OWNED_FIELDS: readonly PlatformOwnedField[];
|
|
66
|
+
export type PlatformOwnedFieldSpec = (typeof FIELD_SPECS)[number];
|
|
67
|
+
export type PlatformOwnedFieldPath = PlatformOwnedFieldSpec["path"];
|
|
68
|
+
export declare function findPlatformOwnedField(path: string): PlatformOwnedField | undefined;
|
|
69
|
+
export declare function formatPlatformFieldDetail(fields: readonly PlatformOwnedField[]): string;
|
|
70
|
+
export {};
|
|
71
|
+
//# sourceMappingURL=platform-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-fields.d.ts","sourceRoot":"","sources":["../src/platform-fields.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,kBAAkB;IAGjC,IAAI,EAAE,MAAM,CAAC;IAIb,MAAM,EAAE,MAAM,CAAC;IAIf,SAAS,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AAMD,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiFiC,CAAC;AAEnD,eAAO,MAAM,qBAAqB,EAAE,SAAS,kBAAkB,EAAgB,CAAC;AAEhF,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAClE,MAAM,MAAM,sBAAsB,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAEpE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEnF;AAKD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAEvF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// The canonical list of VendureConfig fields the platform owns, from ADR-0017's
|
|
2
|
+
// "Platform-owned" category plus the two additions ADR-0023 assigned to it and the
|
|
3
|
+
// `healthChecks` forcing CLO-355 delivers.
|
|
4
|
+
//
|
|
5
|
+
// This list is the single source for four things that must never disagree: the Cloud Config
|
|
6
|
+
// type's branded keys, the runtime backstop, the post-composition assertion, and ADR-0044's
|
|
7
|
+
// converse check. A field added to the type but not to this list is rejected at build time
|
|
8
|
+
// and accepted at boot, so a config assembled at runtime would set it and no check would
|
|
9
|
+
// object.
|
|
10
|
+
// Literal-typed on purpose: cloud-config.ts derives each branded field's explanation from
|
|
11
|
+
// these exact strings, so the build-time message and the runtime message cannot drift.
|
|
12
|
+
// The cost is that an entry without `writtenBy` genuinely lacks the property, so runtime
|
|
13
|
+
// callers iterate PLATFORM_OWNED_FIELDS below rather than this.
|
|
14
|
+
const FIELD_SPECS = [
|
|
15
|
+
{
|
|
16
|
+
path: "dbConnectionOptions",
|
|
17
|
+
reason: "The database connection is supplied by Vendure Cloud, including credential rotation. Remove dbConnectionOptions from your config.",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
path: "logger",
|
|
21
|
+
reason: "Logging is supplied by Vendure Cloud so output reaches the platform log pipeline from the server, the worker and migrations alike. To forward logs elsewhere, use a log drain rather than replacing the logger.",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
path: "apiOptions.port",
|
|
25
|
+
reason: "The port is supplied by Vendure Cloud and must match what the load balancer routes to. Remove apiOptions.port.",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
path: "apiOptions.hostname",
|
|
29
|
+
reason: "The hostname is supplied by Vendure Cloud. Remove apiOptions.hostname.",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
path: "authOptions.superadminCredentials",
|
|
33
|
+
reason: "Vendure Cloud generates the superadmin credential for each environment and surfaces it once. Remove authOptions.superadminCredentials.",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
path: "authOptions.sessionCacheStrategy",
|
|
37
|
+
reason: "The session cache is backed by platform-managed infrastructure. Remove authOptions.sessionCacheStrategy.",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
path: "authOptions.sessionCacheTTL",
|
|
41
|
+
reason: "The session cache TTL is the dominant lever on platform cache cost, so it is a platform decision. Remove authOptions.sessionCacheTTL.",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
path: "systemOptions.cacheStrategy",
|
|
45
|
+
reason: "The cache is supplied by Vendure Cloud. Remove systemOptions.cacheStrategy, and remove RedisCachePlugin from your plugins array.",
|
|
46
|
+
writtenBy: {
|
|
47
|
+
plugin: "RedisCachePlugin",
|
|
48
|
+
replacement: "the platform cache strategy, which is injected automatically",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
path: "systemOptions.healthChecks",
|
|
53
|
+
reason: "The health check is shallow by design: it must not touch the database, because a target group that marks every server unhealthy during a database blip causes ECS to replace all of them at once. Remove systemOptions.healthChecks.",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
path: "assetOptions.assetStorageStrategy",
|
|
57
|
+
reason: "Asset storage is supplied by Vendure Cloud. Remove assetOptions.assetStorageStrategy, and use CloudAssetServerPlugin in place of AssetServerPlugin.",
|
|
58
|
+
writtenBy: {
|
|
59
|
+
plugin: "AssetServerPlugin",
|
|
60
|
+
replacement: "CloudAssetServerPlugin",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
path: "jobQueueOptions.jobQueueStrategy",
|
|
65
|
+
reason: "The job queue is supplied by Vendure Cloud. Remove jobQueueOptions.jobQueueStrategy, and remove BullMQJobQueuePlugin from your plugins array.",
|
|
66
|
+
writtenBy: {
|
|
67
|
+
plugin: "BullMQJobQueuePlugin",
|
|
68
|
+
replacement: "the platform job queue strategy, which is injected automatically",
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
path: "schedulerOptions.schedulerStrategy",
|
|
73
|
+
reason: "Scheduled tasks are driven by Vendure Cloud, because a worker scaled to zero runs none. Remove schedulerOptions.schedulerStrategy, and remove DefaultSchedulerPlugin from your plugins array.",
|
|
74
|
+
writtenBy: {
|
|
75
|
+
plugin: "DefaultSchedulerPlugin",
|
|
76
|
+
replacement: "the platform scheduler strategy, which is injected automatically",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
path: "schedulerOptions.runTasksInWorkerOnly",
|
|
81
|
+
reason: "Vendure Cloud pins runTasksInWorkerOnly to false so the server ticks when the worker is asleep. Remove schedulerOptions.runTasksInWorkerOnly.",
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
export const PLATFORM_OWNED_FIELDS = FIELD_SPECS;
|
|
85
|
+
export function findPlatformOwnedField(path) {
|
|
86
|
+
return PLATFORM_OWNED_FIELDS.find((field) => field.path === path);
|
|
87
|
+
}
|
|
88
|
+
// The shared body of the two boot-time failures. Both name the offending fields the same
|
|
89
|
+
// way, and a customer meeting them one at a time during a migration should not find the
|
|
90
|
+
// two laid out differently.
|
|
91
|
+
export function formatPlatformFieldDetail(fields) {
|
|
92
|
+
return fields.map((field) => ` ${field.path}\n ${field.reason}`).join("\n\n");
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=platform-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-fields.js","sourceRoot":"","sources":["../src/platform-fields.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,mFAAmF;AACnF,2CAA2C;AAC3C,EAAE;AACF,4FAA4F;AAC5F,4FAA4F;AAC5F,2FAA2F;AAC3F,yFAAyF;AACzF,UAAU;AAgBV,0FAA0F;AAC1F,uFAAuF;AACvF,yFAAyF;AACzF,gEAAgE;AAChE,MAAM,WAAW,GAAG;IAClB;QACE,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EACJ,mIAAmI;KACtI;IACD;QACE,IAAI,EAAE,QAAQ;QACd,MAAM,EACJ,iNAAiN;KACpN;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EACJ,gHAAgH;KACnH;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EAAE,wEAAwE;KACjF;IACD;QACE,IAAI,EAAE,mCAAmC;QACzC,MAAM,EACJ,wIAAwI;KAC3I;IACD;QACE,IAAI,EAAE,kCAAkC;QACxC,MAAM,EACJ,0GAA0G;KAC7G;IACD;QACE,IAAI,EAAE,6BAA6B;QACnC,MAAM,EACJ,uIAAuI;KAC1I;IACD;QACE,IAAI,EAAE,6BAA6B;QACnC,MAAM,EACJ,kIAAkI;QACpI,SAAS,EAAE;YACT,MAAM,EAAE,kBAAkB;YAC1B,WAAW,EAAE,8DAA8D;SAC5E;KACF;IACD;QACE,IAAI,EAAE,4BAA4B;QAClC,MAAM,EACJ,sOAAsO;KACzO;IACD;QACE,IAAI,EAAE,mCAAmC;QACzC,MAAM,EACJ,qJAAqJ;QACvJ,SAAS,EAAE;YACT,MAAM,EAAE,mBAAmB;YAC3B,WAAW,EAAE,wBAAwB;SACtC;KACF;IACD;QACE,IAAI,EAAE,kCAAkC;QACxC,MAAM,EACJ,+IAA+I;QACjJ,SAAS,EAAE;YACT,MAAM,EAAE,sBAAsB;YAC9B,WAAW,EAAE,kEAAkE;SAChF;KACF;IACD;QACE,IAAI,EAAE,oCAAoC;QAC1C,MAAM,EACJ,+LAA+L;QACjM,SAAS,EAAE;YACT,MAAM,EAAE,wBAAwB;YAChC,WAAW,EAAE,kEAAkE;SAChF;KACF;IACD;QACE,IAAI,EAAE,uCAAuC;QAC7C,MAAM,EACJ,+IAA+I;KAClJ;CAC+C,CAAC;AAEnD,MAAM,CAAC,MAAM,qBAAqB,GAAkC,WAAW,CAAC;AAKhF,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACpE,CAAC;AAED,yFAAyF;AACzF,wFAAwF;AACxF,4BAA4B;AAC5B,MAAM,UAAU,yBAAyB,CAAC,MAAqC;IAC7E,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,SAAS,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { CloudConfigError } from "./errors.js";
|
|
3
|
+
import { type PlatformOwnedField } from "./platform-fields.js";
|
|
4
|
+
export declare const PLUGIN_CONFIGURATION_METADATA_KEY = "configuration";
|
|
5
|
+
export type PluginConstructor = abstract new (...args: never[]) => unknown;
|
|
6
|
+
export type PluginLike = PluginConstructor | {
|
|
7
|
+
readonly module: PluginConstructor;
|
|
8
|
+
};
|
|
9
|
+
export interface PlatformFieldWrite {
|
|
10
|
+
plugin: string;
|
|
11
|
+
field: PlatformOwnedField;
|
|
12
|
+
extension?: string;
|
|
13
|
+
}
|
|
14
|
+
export type ExtensionOfPlugin = ReadonlyMap<PluginLike, {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
}>;
|
|
17
|
+
export declare function pluginName(plugin: PluginLike): string;
|
|
18
|
+
export interface PendingPlatformFieldWrites {
|
|
19
|
+
readonly writes: readonly PlatformFieldWrite[];
|
|
20
|
+
}
|
|
21
|
+
export declare function recordPlatformFieldWrites(plugins: readonly PluginLike[], extensionOf?: ExtensionOfPlugin): PendingPlatformFieldWrites;
|
|
22
|
+
export declare class PlatformFieldSetByPluginError extends CloudConfigError {
|
|
23
|
+
readonly writes: readonly PlatformFieldWrite[];
|
|
24
|
+
constructor(writes: readonly PlatformFieldWrite[]);
|
|
25
|
+
}
|
|
26
|
+
export declare function assertNoCustomerPluginWroteAPlatformField(writes: readonly PlatformFieldWrite[], cloudPluginNames: readonly string[]): void;
|
|
27
|
+
//# sourceMappingURL=plugin-attribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-attribution.d.ts","sourceRoot":"","sources":["../src/plugin-attribution.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAyB,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAWtF,eAAO,MAAM,iCAAiC,kBAAkB,CAAC;AAIjE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC;AAC3E,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEpF,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,kBAAkB,CAAC;IAI1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC,UAAU,EAAE;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AASjF,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAIrD;AAsBD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAChD;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,WAAW,GAAE,iBAA6B,GACzC,0BAA0B,CA0C5B;AAYD,qBAAa,6BAA8B,SAAQ,gBAAgB;IACjE,QAAQ,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,CAAC;gBAEnC,MAAM,EAAE,SAAS,kBAAkB,EAAE;CAiBlD;AAED,wBAAgB,yCAAyC,CACvD,MAAM,EAAE,SAAS,kBAAkB,EAAE,EACrC,gBAAgB,EAAE,SAAS,MAAM,EAAE,GAClC,IAAI,CAKN"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { CloudConfigError } from "./errors.js";
|
|
3
|
+
import { readPath } from "./path.js";
|
|
4
|
+
import { PLATFORM_OWNED_FIELDS } from "./platform-fields.js";
|
|
5
|
+
// Core reads a plugin's configuration function out of this metadata key
|
|
6
|
+
// (`PLUGIN_METADATA.CONFIGURATION` in @vendure/core). It is restated rather than imported so
|
|
7
|
+
// this package needs no runtime dependency on core. That keeps it a thin interface package,
|
|
8
|
+
// and it means the package cannot itself load a second copy of `@vendure/core` — the failure
|
|
9
|
+
// ADR-0043 measured, where the application's `Logger` and the platform's are different
|
|
10
|
+
// classes and every log line goes to the one nobody reads.
|
|
11
|
+
//
|
|
12
|
+
// A test pins this string to core's real value, so a rename there fails our build rather
|
|
13
|
+
// than silently disabling attribution.
|
|
14
|
+
export const PLUGIN_CONFIGURATION_METADATA_KEY = "configuration";
|
|
15
|
+
function metadataTarget(plugin) {
|
|
16
|
+
if (typeof plugin === "object" && plugin !== null && "module" in plugin) {
|
|
17
|
+
return plugin.module;
|
|
18
|
+
}
|
|
19
|
+
return plugin;
|
|
20
|
+
}
|
|
21
|
+
export function pluginName(plugin) {
|
|
22
|
+
const target = metadataTarget(plugin);
|
|
23
|
+
const named = target.name;
|
|
24
|
+
return typeof named === "string" && named.length > 0 ? named : "an anonymous plugin";
|
|
25
|
+
}
|
|
26
|
+
function snapshotPlatformFields(config) {
|
|
27
|
+
return new Map(PLATFORM_OWNED_FIELDS.map((field) => [field.path, readPath(config, field.path)]));
|
|
28
|
+
}
|
|
29
|
+
export function recordPlatformFieldWrites(plugins, extensionOf = new Map()) {
|
|
30
|
+
const writes = [];
|
|
31
|
+
// Guards against wrapping one configuration function twice. A plugins array holding the
|
|
32
|
+
// same reference twice, or a class and a DynamicModule around that same class, resolves to
|
|
33
|
+
// one metadata target: without this, the second pass reads the first wrapper back as the
|
|
34
|
+
// "original" and wraps it again, so every execution of that plugin records its writes twice
|
|
35
|
+
// and the boot message reports writes the plugin did not make.
|
|
36
|
+
const wrappedTargets = new WeakSet();
|
|
37
|
+
for (const plugin of plugins) {
|
|
38
|
+
const target = metadataTarget(plugin);
|
|
39
|
+
if (wrappedTargets.has(target))
|
|
40
|
+
continue;
|
|
41
|
+
const original = Reflect.getMetadata(PLUGIN_CONFIGURATION_METADATA_KEY, target);
|
|
42
|
+
if (typeof original !== "function")
|
|
43
|
+
continue;
|
|
44
|
+
const name = pluginName(plugin);
|
|
45
|
+
// The extension is read at the array entry that gets wrapped. For a plugin appearing
|
|
46
|
+
// more than once, that is the first entry: core keeps the configuration function on the
|
|
47
|
+
// class, so one wrapper covers every execution and there is no finer attribution to be
|
|
48
|
+
// had.
|
|
49
|
+
const extension = extensionOf.get(plugin)?.id;
|
|
50
|
+
const configure = original;
|
|
51
|
+
const wrapped = async (config) => {
|
|
52
|
+
const before = snapshotPlatformFields(config);
|
|
53
|
+
const result = await configure(config);
|
|
54
|
+
const after = snapshotPlatformFields(result ?? config);
|
|
55
|
+
for (const field of PLATFORM_OWNED_FIELDS) {
|
|
56
|
+
if (!Object.is(before.get(field.path), after.get(field.path))) {
|
|
57
|
+
writes.push({ plugin: name, field, extension });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
};
|
|
62
|
+
Reflect.defineMetadata(PLUGIN_CONFIGURATION_METADATA_KEY, wrapped, target);
|
|
63
|
+
wrappedTargets.add(target);
|
|
64
|
+
}
|
|
65
|
+
return { writes };
|
|
66
|
+
}
|
|
67
|
+
// ADR-0044's converse check. Cloud Plugins run last, so a customer plugin that wrote a
|
|
68
|
+
// platform-owned field has already had its value overwritten. The customer set something,
|
|
69
|
+
// saw no error, and is running with a different value than they wrote.
|
|
70
|
+
//
|
|
71
|
+
// The message names the plugin and the Cloud Plugin that replaces it, and the Vendure
|
|
72
|
+
// Extension the plugin came from where one declared it. Naming only the offending plugin
|
|
73
|
+
// leaves the customer knowing a line is wrong and not what to write instead, which turns a
|
|
74
|
+
// one-line edit into a support ticket. The extension is named for the same reason: a plugin
|
|
75
|
+
// declared inside one is not written in the config file at all, so its class name does not
|
|
76
|
+
// say which line to look at.
|
|
77
|
+
export class PlatformFieldSetByPluginError extends CloudConfigError {
|
|
78
|
+
writes;
|
|
79
|
+
constructor(writes) {
|
|
80
|
+
const detail = writes
|
|
81
|
+
.map(({ plugin, field, extension }) => {
|
|
82
|
+
const replacement = field.writtenBy?.replacement ?? "the platform equivalent, which is supplied for you";
|
|
83
|
+
const offender = extension === undefined ? plugin : `${plugin}, in the Vendure Extension "${extension}",`;
|
|
84
|
+
return ` ${offender} set ${field.path}, which Vendure Cloud supplies.\n Use ${replacement}.`;
|
|
85
|
+
})
|
|
86
|
+
.join("\n\n");
|
|
87
|
+
super(`Vendure Cloud: ${writes.length} plugin write${writes.length === 1 ? "" : "s"} to platform-owned configuration would be discarded. Refusing to boot.\n\n${detail}\n`);
|
|
88
|
+
this.writes = writes;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function assertNoCustomerPluginWroteAPlatformField(writes, cloudPluginNames) {
|
|
92
|
+
const offending = writes.filter((write) => !cloudPluginNames.includes(write.plugin));
|
|
93
|
+
if (offending.length > 0) {
|
|
94
|
+
throw new PlatformFieldSetByPluginError(offending);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=plugin-attribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-attribution.js","sourceRoot":"","sources":["../src/plugin-attribution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CloudConfigError } from "./errors.js";
|
|
2
|
+
import { type PlatformOwnedField } from "./platform-fields.js";
|
|
3
|
+
export declare function listPlatformOwnedFieldsSetIn(config: unknown): PlatformOwnedField[];
|
|
4
|
+
export declare class PlatformFieldSetByConfigError extends CloudConfigError {
|
|
5
|
+
readonly fields: readonly PlatformOwnedField[];
|
|
6
|
+
constructor(fields: readonly PlatformOwnedField[]);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=runtime-backstop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-backstop.d.ts","sourceRoot":"","sources":["../src/runtime-backstop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAQ9B,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,OAAO,GAAG,kBAAkB,EAAE,CAElF;AAED,qBAAa,6BAA8B,SAAQ,gBAAgB;IACjE,QAAQ,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,CAAC;gBAEnC,MAAM,EAAE,SAAS,kBAAkB,EAAE;CASlD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CloudConfigError } from "./errors.js";
|
|
2
|
+
import { readPath } from "./path.js";
|
|
3
|
+
import { PLATFORM_OWNED_FIELDS, formatPlatformFieldDetail, } from "./platform-fields.js";
|
|
4
|
+
// The build-time guarantee holds for a config written as an object literal and is absent
|
|
5
|
+
// for one assembled programmatically, which no type can reach. ADR-0043 requires this
|
|
6
|
+
// check so that second case fails loudly at boot rather than silently at runtime.
|
|
7
|
+
// A key present but undefined is not a violation: that is what spreading an optional
|
|
8
|
+
// object produces, and the customer expressed no intent. Only a set value counts.
|
|
9
|
+
export function listPlatformOwnedFieldsSetIn(config) {
|
|
10
|
+
return PLATFORM_OWNED_FIELDS.filter((field) => readPath(config, field.path) !== undefined);
|
|
11
|
+
}
|
|
12
|
+
export class PlatformFieldSetByConfigError extends CloudConfigError {
|
|
13
|
+
fields;
|
|
14
|
+
constructor(fields) {
|
|
15
|
+
const detail = formatPlatformFieldDetail(fields);
|
|
16
|
+
super(`Vendure Cloud: this configuration sets ${fields.length} field${fields.length === 1 ? "" : "s"} that the platform supplies.\n\n${detail}\n`);
|
|
17
|
+
this.fields = fields;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=runtime-backstop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-backstop.js","sourceRoot":"","sources":["../src/runtime-backstop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EACL,qBAAqB,EACrB,yBAAyB,GAE1B,MAAM,sBAAsB,CAAC;AAE9B,yFAAyF;AACzF,sFAAsF;AACtF,kFAAkF;AAElF,qFAAqF;AACrF,kFAAkF;AAClF,MAAM,UAAU,4BAA4B,CAAC,MAAe;IAC1D,OAAO,qBAAqB,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,OAAO,6BAA8B,SAAQ,gBAAgB;IACxD,MAAM,CAAgC;IAE/C,YAAY,MAAqC;QAC/C,MAAM,MAAM,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;QACjD,KAAK,CACH,0CAA0C,MAAM,CAAC,MAAM,SACrD,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAC7B,mCAAmC,MAAM,IAAI,CAC9C,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}
|