@salesforce/vite-plugin-lwc-ui-bundle 11.13.2 → 11.15.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/dist/index.d.ts +33 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +103 -6
- package/dist/index.js.map +1 -1
- package/dist/plugins/generate-meta-xml.d.ts +13 -0
- package/dist/plugins/generate-meta-xml.d.ts.map +1 -0
- package/dist/providers/access-check.d.ts.map +1 -1
- package/dist/providers/gate.d.ts.map +1 -1
- package/dist/providers/i18n.d.ts +16 -0
- package/dist/providers/i18n.d.ts.map +1 -1
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +3 -178
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/labels-graphql/index.d.ts.map +1 -1
- package/dist/providers/labels-graphql/index.js +12 -3
- package/dist/providers/labels-graphql/index.js.map +1 -1
- package/dist/providers/labels-graphql/runtime.d.ts +21 -14
- package/dist/providers/labels-graphql/runtime.d.ts.map +1 -1
- package/dist/providers/labels-graphql/runtime.js +39 -26
- package/dist/providers/labels-graphql/runtime.js.map +1 -1
- package/dist/providers/platform-graphql/constants.d.ts +15 -0
- package/dist/providers/platform-graphql/constants.d.ts.map +1 -0
- package/dist/providers/platform-graphql/i18n-static.d.ts +19 -0
- package/dist/providers/platform-graphql/i18n-static.d.ts.map +1 -0
- package/dist/providers/platform-graphql/index.d.ts +58 -0
- package/dist/providers/platform-graphql/index.d.ts.map +1 -0
- package/dist/providers/platform-graphql/index.js +312 -0
- package/dist/providers/platform-graphql/index.js.map +1 -0
- package/dist/providers/platform-graphql/runtime.d.ts +30 -0
- package/dist/providers/platform-graphql/runtime.d.ts.map +1 -0
- package/dist/providers/platform-graphql/runtime.js +189 -0
- package/dist/providers/platform-graphql/runtime.js.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/consumer-guide.md +120 -4
- package/package.json +5 -5
- package/skills/setup-lwc-vite-plugin/SKILL.md +44 -1
- package/skills/setup-lwc-vite-plugin/references/known-pitfalls.md +57 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
const permState = {
|
|
2
|
+
cache: /* @__PURE__ */ new Map(),
|
|
3
|
+
pending: /* @__PURE__ */ new Set(),
|
|
4
|
+
scheduled: false,
|
|
5
|
+
subscribers: /* @__PURE__ */ new Map()
|
|
6
|
+
};
|
|
7
|
+
const customPermState = {
|
|
8
|
+
cache: /* @__PURE__ */ new Map(),
|
|
9
|
+
pending: /* @__PURE__ */ new Set(),
|
|
10
|
+
scheduled: false,
|
|
11
|
+
subscribers: /* @__PURE__ */ new Map()
|
|
12
|
+
};
|
|
13
|
+
const i18nState = {
|
|
14
|
+
cache: /* @__PURE__ */ new Map(),
|
|
15
|
+
pending: /* @__PURE__ */ new Set(),
|
|
16
|
+
scheduled: false,
|
|
17
|
+
subscribers: /* @__PURE__ */ new Map()
|
|
18
|
+
};
|
|
19
|
+
let probePromise = null;
|
|
20
|
+
const I18N_GRAPHQL_KEYS = [
|
|
21
|
+
"lang",
|
|
22
|
+
"dir",
|
|
23
|
+
"locale",
|
|
24
|
+
"currency",
|
|
25
|
+
"timeZone",
|
|
26
|
+
"firstDayOfWeek",
|
|
27
|
+
"defaultCalendar",
|
|
28
|
+
"defaultNumberingSystem"
|
|
29
|
+
];
|
|
30
|
+
const I18N_NUMERIC_KEYS = /* @__PURE__ */ new Set(["firstDayOfWeek"]);
|
|
31
|
+
const PERM_QUERY = `query UserPermissions($names: [String!]!) {
|
|
32
|
+
uiapi { platform { userPermissions(names: $names) { name hasAccess } } }
|
|
33
|
+
}`;
|
|
34
|
+
const CUSTOM_PERM_QUERY = `query CustomPermissions($names: [String!]!) {
|
|
35
|
+
uiapi { platform { customPermissions(names: $names) { name hasAccess } } }
|
|
36
|
+
}`;
|
|
37
|
+
const I18N_QUERY = `query I18n {
|
|
38
|
+
uiapi { platform { i18n { ${I18N_GRAPHQL_KEYS.join(" ")} } } }
|
|
39
|
+
}`;
|
|
40
|
+
async function detectPlatformPath() {
|
|
41
|
+
try {
|
|
42
|
+
const response = await graphqlFetch(`{ uiapi { platform { __typename } } }`, {});
|
|
43
|
+
return !!response?.data?.uiapi?.platform;
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function getApiShape() {
|
|
49
|
+
if (!probePromise) {
|
|
50
|
+
probePromise = detectPlatformPath();
|
|
51
|
+
}
|
|
52
|
+
return probePromise;
|
|
53
|
+
}
|
|
54
|
+
function notify(state, key, value) {
|
|
55
|
+
if (state.cache.get(key) === value) return;
|
|
56
|
+
state.cache.set(key, value);
|
|
57
|
+
const set = state.subscribers.get(key);
|
|
58
|
+
if (set) for (const cb of set) cb(value);
|
|
59
|
+
}
|
|
60
|
+
function subscribeTo(state, key, current, callback) {
|
|
61
|
+
let set = state.subscribers.get(key);
|
|
62
|
+
if (!set) {
|
|
63
|
+
set = /* @__PURE__ */ new Set();
|
|
64
|
+
state.subscribers.set(key, set);
|
|
65
|
+
}
|
|
66
|
+
set.add(callback);
|
|
67
|
+
callback(current());
|
|
68
|
+
return () => {
|
|
69
|
+
state.subscribers.get(key)?.delete(callback);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function getUserPermission(name, fallback) {
|
|
73
|
+
if (permState.cache.has(name)) return permState.cache.get(name);
|
|
74
|
+
permState.cache.set(name, fallback);
|
|
75
|
+
permState.pending.add(name);
|
|
76
|
+
schedulePermFetch(permState, PERM_QUERY, "userPermissions");
|
|
77
|
+
return fallback;
|
|
78
|
+
}
|
|
79
|
+
function subscribeUserPermission(name, fallback, cb) {
|
|
80
|
+
return subscribeTo(permState, name, () => getUserPermission(name, fallback), cb);
|
|
81
|
+
}
|
|
82
|
+
function getCustomPermission(name, fallback) {
|
|
83
|
+
if (customPermState.cache.has(name)) return customPermState.cache.get(name);
|
|
84
|
+
customPermState.cache.set(name, fallback);
|
|
85
|
+
customPermState.pending.add(name);
|
|
86
|
+
schedulePermFetch(customPermState, CUSTOM_PERM_QUERY, "customPermissions");
|
|
87
|
+
return fallback;
|
|
88
|
+
}
|
|
89
|
+
function subscribeCustomPermission(name, fallback, cb) {
|
|
90
|
+
return subscribeTo(customPermState, name, () => getCustomPermission(name, fallback), cb);
|
|
91
|
+
}
|
|
92
|
+
function schedulePermFetch(state, query, field) {
|
|
93
|
+
if (state.scheduled) return;
|
|
94
|
+
state.scheduled = true;
|
|
95
|
+
Promise.resolve().then(() => {
|
|
96
|
+
state.scheduled = false;
|
|
97
|
+
if (state.pending.size === 0) return;
|
|
98
|
+
const names = [...state.pending];
|
|
99
|
+
state.pending.clear();
|
|
100
|
+
fetchPermissions(state, query, field, names);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async function fetchPermissions(state, query, field, names) {
|
|
104
|
+
if (!await getApiShape()) return;
|
|
105
|
+
for (let i = 0; i < names.length; i += 100) {
|
|
106
|
+
const batch = names.slice(i, i + 100);
|
|
107
|
+
try {
|
|
108
|
+
const response = await graphqlFetch(query, { names: batch });
|
|
109
|
+
const records = response?.data?.uiapi?.platform?.[field] ?? [];
|
|
110
|
+
for (const rec of records) {
|
|
111
|
+
if (!rec) continue;
|
|
112
|
+
notify(state, rec.name, !!rec.hasAccess);
|
|
113
|
+
}
|
|
114
|
+
} catch (e) {
|
|
115
|
+
console.warn(`[platform-graphql] ${field} fetch failed:`, e);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function getI18n(key, fallback) {
|
|
120
|
+
if (i18nState.cache.has(key)) return i18nState.cache.get(key);
|
|
121
|
+
i18nState.cache.set(key, fallback);
|
|
122
|
+
scheduleI18nFetch();
|
|
123
|
+
return fallback;
|
|
124
|
+
}
|
|
125
|
+
function subscribeI18n(key, fallback, cb) {
|
|
126
|
+
return subscribeTo(i18nState, key, () => getI18n(key, fallback), cb);
|
|
127
|
+
}
|
|
128
|
+
function scheduleI18nFetch() {
|
|
129
|
+
if (i18nState.scheduled) return;
|
|
130
|
+
i18nState.scheduled = true;
|
|
131
|
+
Promise.resolve().then(() => {
|
|
132
|
+
i18nState.scheduled = false;
|
|
133
|
+
fetchI18n();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async function fetchI18n() {
|
|
137
|
+
if (!await getApiShape()) return;
|
|
138
|
+
try {
|
|
139
|
+
const response = await graphqlFetch(I18N_QUERY, {});
|
|
140
|
+
const payload = response?.data?.uiapi?.platform?.i18n;
|
|
141
|
+
if (!payload) return;
|
|
142
|
+
for (const k of I18N_GRAPHQL_KEYS) {
|
|
143
|
+
if (payload[k] == null) continue;
|
|
144
|
+
const value = I18N_NUMERIC_KEYS.has(k) ? Number(payload[k]) : String(payload[k]);
|
|
145
|
+
notify(i18nState, k, value);
|
|
146
|
+
}
|
|
147
|
+
} catch (e) {
|
|
148
|
+
console.warn("[platform-graphql] i18n fetch failed:", e);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async function graphqlFetch(query, variables) {
|
|
152
|
+
let createDataSDK;
|
|
153
|
+
try {
|
|
154
|
+
({ createDataSDK } = await import("@salesforce/platform-sdk"));
|
|
155
|
+
} catch {
|
|
156
|
+
console.warn(
|
|
157
|
+
"[platform-graphql] @salesforce/platform-sdk is not available. Using fallback values."
|
|
158
|
+
);
|
|
159
|
+
return {};
|
|
160
|
+
}
|
|
161
|
+
if (typeof createDataSDK !== "function") return {};
|
|
162
|
+
const sdk = await createDataSDK();
|
|
163
|
+
if (!sdk.graphql) return {};
|
|
164
|
+
const result = await sdk.graphql.query({ query, variables });
|
|
165
|
+
return { data: result.data, errors: result.errors };
|
|
166
|
+
}
|
|
167
|
+
function __resetForTest() {
|
|
168
|
+
for (const s of [permState, customPermState, i18nState]) {
|
|
169
|
+
s.cache.clear();
|
|
170
|
+
s.pending.clear();
|
|
171
|
+
s.scheduled = false;
|
|
172
|
+
s.subscribers.clear();
|
|
173
|
+
}
|
|
174
|
+
probePromise = null;
|
|
175
|
+
}
|
|
176
|
+
export {
|
|
177
|
+
I18N_GRAPHQL_KEYS,
|
|
178
|
+
I18N_NUMERIC_KEYS,
|
|
179
|
+
__resetForTest,
|
|
180
|
+
getApiShape,
|
|
181
|
+
getCustomPermission,
|
|
182
|
+
getI18n,
|
|
183
|
+
getUserPermission,
|
|
184
|
+
graphqlFetch,
|
|
185
|
+
subscribeCustomPermission,
|
|
186
|
+
subscribeI18n,
|
|
187
|
+
subscribeUserPermission
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sources":["../../../src/providers/platform-graphql/runtime.ts"],"sourcesContent":["/**\n * Copyright (c) 2026, Salesforce, Inc.,\n * All rights reserved.\n * For full license text, see the LICENSE.txt file\n */\n\n/**\n * Shared runtime for scoped modules that resolve via `uiapi.platform.*` GraphQL\n * off-core through the Platform Data SDK:\n *\n * - `@salesforce/userPermission/<Name>` → `userPermissions(names:)` → boolean\n * - `@salesforce/accessCheck/<Name>` → `userPermissions(names:)` → boolean\n * - `@salesforce/customPermission/<Name>` → `customPermissions(names:)` → boolean\n * - `@salesforce/i18n/<key>` → `i18n { ... }` (locale identity)\n *\n * Like the labels runtime, each accessor returns a synchronous value (the\n * build-time fallback) immediately and schedules a batched GraphQL fetch; the\n * resolved org value lands in the cache and notifies subscribers. Components opt\n * into reactivity via the generated module's `subscribe(cb)` export.\n */\n\ninterface DomainState<V> {\n\tcache: Map<string, V>;\n\tpending: Set<string>;\n\tscheduled: boolean;\n\tsubscribers: Map<string, Set<(value: V) => void>>;\n}\n\nconst permState: DomainState<boolean> = {\n\tcache: new Map(),\n\tpending: new Set(),\n\tscheduled: false,\n\tsubscribers: new Map(),\n};\nconst customPermState: DomainState<boolean> = {\n\tcache: new Map(),\n\tpending: new Set(),\n\tscheduled: false,\n\tsubscribers: new Map(),\n};\n// i18n values are mostly strings, but a few keys are contractually numeric\n// (see I18N_NUMERIC_KEYS) so the domain is `string | number`.\nconst i18nState: DomainState<string | number> = {\n\tcache: new Map(),\n\tpending: new Set(),\n\tscheduled: false,\n\tsubscribers: new Map(),\n};\n\nlet probePromise: Promise<boolean> | null = null;\n\n/** i18n scalar fields exposed by `uiapi.platform.i18n` (locale identity). */\nexport const I18N_GRAPHQL_KEYS = [\n\t\"lang\",\n\t\"dir\",\n\t\"locale\",\n\t\"currency\",\n\t\"timeZone\",\n\t\"firstDayOfWeek\",\n\t\"defaultCalendar\",\n\t\"defaultNumberingSystem\",\n] as const;\n\n/**\n * i18n identity keys whose `@salesforce/i18n/*` contract is a NUMBER, not a\n * string (e.g. `firstDayOfWeek` is `1`=Mon … `7`=Sun). These are coerced with\n * `Number()` rather than `String()` so consumers that do arithmetic or strict\n * equality on them keep working. All other identity keys are strings.\n */\nexport const I18N_NUMERIC_KEYS = new Set<string>([\"firstDayOfWeek\"]);\n\nconst PERM_QUERY = `query UserPermissions($names: [String!]!) {\n uiapi { platform { userPermissions(names: $names) { name hasAccess } } }\n}`;\n\nconst CUSTOM_PERM_QUERY = `query CustomPermissions($names: [String!]!) {\n uiapi { platform { customPermissions(names: $names) { name hasAccess } } }\n}`;\n\nconst I18N_QUERY = `query I18n {\n uiapi { platform { i18n { ${I18N_GRAPHQL_KEYS.join(\" \")} } } }\n}`;\n\nasync function detectPlatformPath(): Promise<boolean> {\n\ttry {\n\t\tconst response = (await graphqlFetch(`{ uiapi { platform { __typename } } }`, {})) as {\n\t\t\tdata?: { uiapi?: { platform?: unknown } };\n\t\t};\n\t\treturn !!response?.data?.uiapi?.platform;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport function getApiShape(): Promise<boolean> {\n\tif (!probePromise) {\n\t\tprobePromise = detectPlatformPath();\n\t}\n\treturn probePromise;\n}\n\nfunction notify<V>(state: DomainState<V>, key: string, value: V): void {\n\tif (state.cache.get(key) === value) return;\n\tstate.cache.set(key, value);\n\tconst set = state.subscribers.get(key);\n\tif (set) for (const cb of set) cb(value);\n}\n\nfunction subscribeTo<V>(\n\tstate: DomainState<V>,\n\tkey: string,\n\tcurrent: () => V,\n\tcallback: (value: V) => void,\n): () => void {\n\tlet set = state.subscribers.get(key);\n\tif (!set) {\n\t\tset = new Set();\n\t\tstate.subscribers.set(key, set);\n\t}\n\tset.add(callback);\n\tcallback(current());\n\treturn () => {\n\t\tstate.subscribers.get(key)?.delete(callback);\n\t};\n}\n\n// ── Permissions (userPermissions / accessCheck) ──────────────────────────────\n\nexport function getUserPermission(name: string, fallback: boolean): boolean {\n\tif (permState.cache.has(name)) return permState.cache.get(name)!;\n\tpermState.cache.set(name, fallback);\n\tpermState.pending.add(name);\n\tschedulePermFetch(permState, PERM_QUERY, \"userPermissions\");\n\treturn fallback;\n}\n\nexport function subscribeUserPermission(\n\tname: string,\n\tfallback: boolean,\n\tcb: (v: boolean) => void,\n): () => void {\n\treturn subscribeTo(permState, name, () => getUserPermission(name, fallback), cb);\n}\n\nexport function getCustomPermission(name: string, fallback: boolean): boolean {\n\tif (customPermState.cache.has(name)) return customPermState.cache.get(name)!;\n\tcustomPermState.cache.set(name, fallback);\n\tcustomPermState.pending.add(name);\n\tschedulePermFetch(customPermState, CUSTOM_PERM_QUERY, \"customPermissions\");\n\treturn fallback;\n}\n\nexport function subscribeCustomPermission(\n\tname: string,\n\tfallback: boolean,\n\tcb: (v: boolean) => void,\n): () => void {\n\treturn subscribeTo(customPermState, name, () => getCustomPermission(name, fallback), cb);\n}\n\ninterface PermissionRecord {\n\tname: string;\n\thasAccess: boolean;\n}\n\nfunction schedulePermFetch(\n\tstate: DomainState<boolean>,\n\tquery: string,\n\tfield: \"userPermissions\" | \"customPermissions\",\n): void {\n\tif (state.scheduled) return;\n\tstate.scheduled = true;\n\tPromise.resolve().then(() => {\n\t\tstate.scheduled = false;\n\t\tif (state.pending.size === 0) return;\n\t\tconst names = [...state.pending];\n\t\tstate.pending.clear();\n\t\tfetchPermissions(state, query, field, names);\n\t});\n}\n\nasync function fetchPermissions(\n\tstate: DomainState<boolean>,\n\tquery: string,\n\tfield: \"userPermissions\" | \"customPermissions\",\n\tnames: string[],\n): Promise<void> {\n\t// platform.* path is required for these fields; if absent, keep fallbacks.\n\tif (!(await getApiShape())) return;\n\tfor (let i = 0; i < names.length; i += 100) {\n\t\tconst batch = names.slice(i, i + 100);\n\t\ttry {\n\t\t\tconst response = (await graphqlFetch(query, { names: batch })) as {\n\t\t\t\tdata?: { uiapi?: { platform?: Record<string, PermissionRecord[]> } };\n\t\t\t};\n\t\t\tconst records = response?.data?.uiapi?.platform?.[field] ?? [];\n\t\t\tfor (const rec of records) {\n\t\t\t\t// An unknown/invalid name yields a `null` array entry (with a\n\t\t\t\t// matching ValidationError in `errors`), positionally aligned with\n\t\t\t\t// the requested name. Skip it so one bad name in a mixed batch does\n\t\t\t\t// not abort resolution for the valid names alongside it — their\n\t\t\t\t// fallbacks would otherwise silently stick.\n\t\t\t\tif (!rec) continue;\n\t\t\t\tnotify(state, rec.name, !!rec.hasAccess);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconsole.warn(`[platform-graphql] ${field} fetch failed:`, e);\n\t\t}\n\t}\n}\n\n// ── i18n (locale identity) ───────────────────────────────────────────────────\n\nexport function getI18n(key: string, fallback: string | number): string | number {\n\tif (i18nState.cache.has(key)) return i18nState.cache.get(key)!;\n\ti18nState.cache.set(key, fallback);\n\t// Any i18n key triggers a single fetch that resolves ALL identity fields at\n\t// once, so there is no per-key pending set to track (unlike permissions).\n\tscheduleI18nFetch();\n\treturn fallback;\n}\n\nexport function subscribeI18n(\n\tkey: string,\n\tfallback: string | number,\n\tcb: (v: string | number) => void,\n): () => void {\n\treturn subscribeTo(i18nState, key, () => getI18n(key, fallback), cb);\n}\n\nfunction scheduleI18nFetch(): void {\n\tif (i18nState.scheduled) return;\n\ti18nState.scheduled = true;\n\tPromise.resolve().then(() => {\n\t\ti18nState.scheduled = false;\n\t\tfetchI18n();\n\t});\n}\n\nasync function fetchI18n(): Promise<void> {\n\tif (!(await getApiShape())) return;\n\ttry {\n\t\tconst response = (await graphqlFetch(I18N_QUERY, {})) as {\n\t\t\tdata?: { uiapi?: { platform?: { i18n?: Record<string, unknown> } } };\n\t\t};\n\t\tconst payload = response?.data?.uiapi?.platform?.i18n;\n\t\tif (!payload) return;\n\t\tfor (const k of I18N_GRAPHQL_KEYS) {\n\t\t\tif (payload[k] == null) continue;\n\t\t\t// firstDayOfWeek (and any other numeric-contract key) stays a number;\n\t\t\t// everything else is a string. See I18N_NUMERIC_KEYS.\n\t\t\tconst value = I18N_NUMERIC_KEYS.has(k) ? Number(payload[k]) : String(payload[k]);\n\t\t\tnotify(i18nState, k, value);\n\t\t}\n\t} catch (e) {\n\t\tconsole.warn(\"[platform-graphql] i18n fetch failed:\", e);\n\t}\n}\n\n// ── Shared SDK transport ─────────────────────────────────────────────────────\n\n/**\n * Fetch through the Platform Data SDK — surface-aware (direct session GraphQL on\n * WebApp/MFE, window.openai bridge on OpenAI/MCP). Returns `{}` when no data\n * surface is available, so callers keep their build-time fallbacks.\n */\nexport async function graphqlFetch(\n\tquery: string,\n\tvariables: Record<string, unknown>,\n): Promise<unknown> {\n\tlet createDataSDK:\n\t\t| ((options?: unknown) => Promise<{\n\t\t\t\tgraphql?: { query: (opts: unknown) => Promise<{ data?: unknown; errors?: unknown }> };\n\t\t }>)\n\t\t| undefined;\n\ttry {\n\t\t({ createDataSDK } = (await import(\"@salesforce/platform-sdk\")) as unknown as {\n\t\t\tcreateDataSDK: typeof createDataSDK;\n\t\t});\n\t} catch {\n\t\tconsole.warn(\n\t\t\t\"[platform-graphql] @salesforce/platform-sdk is not available. Using fallback values.\",\n\t\t);\n\t\treturn {};\n\t}\n\tif (typeof createDataSDK !== \"function\") return {};\n\tconst sdk = await createDataSDK();\n\tif (!sdk.graphql) return {};\n\tconst result = await sdk.graphql.query({ query, variables });\n\treturn { data: result.data, errors: result.errors };\n}\n\n/** Reset internal state — exposed for tests only. */\nexport function __resetForTest(): void {\n\tfor (const s of [permState, customPermState, i18nState]) {\n\t\ts.cache.clear();\n\t\ts.pending.clear();\n\t\ts.scheduled = false;\n\t\ts.subscribers.clear();\n\t}\n\tprobePromise = null;\n}\n"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { UIBundleTarget } from '@salesforce/ui-bundle/app';
|
|
1
2
|
import { Plugin } from 'vite';
|
|
2
3
|
export interface Provider {
|
|
3
4
|
prefix?: string;
|
|
@@ -27,6 +28,34 @@ export interface LwcVitePluginOptions {
|
|
|
27
28
|
ignorePatterns?: string[];
|
|
28
29
|
passthroughRules?: PassthroughRule[];
|
|
29
30
|
bundle?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Write the bundle's `*.uibundle-meta.xml` at build time, deriving its
|
|
33
|
+
* `<target>` element from {@link GenerateMetaXmlOptions.target}. The target
|
|
34
|
+
* is configured here, NOT in `ui-bundle.json` — the platform's manifest
|
|
35
|
+
* schema rejects a `target` field. `ui-bundle.json` (at the project root) is
|
|
36
|
+
* read only for the master-label fallback (`manifest.name`).
|
|
37
|
+
*
|
|
38
|
+
* Generation runs only when a `target` is supplied; without one there is
|
|
39
|
+
* nothing to contribute over a hand-authored meta XML. Enabled by default
|
|
40
|
+
* but inert until you pass a `target`. Set to `false` to disable outright,
|
|
41
|
+
* or pass an object to configure the target, paths, and metadata.
|
|
42
|
+
*/
|
|
43
|
+
generateMetaXml?: boolean | GenerateMetaXmlOptions;
|
|
44
|
+
}
|
|
45
|
+
export interface GenerateMetaXmlOptions {
|
|
46
|
+
/**
|
|
47
|
+
* Deployment target for the bundle: "Experience", "CustomApplication", or
|
|
48
|
+
* "AppLauncher" (an alias for CustomApplication). Drives the generated
|
|
49
|
+
* `*.uibundle-meta.xml` `<target>`. Supplied here rather than in
|
|
50
|
+
* `ui-bundle.json` because the platform's manifest schema rejects a `target`
|
|
51
|
+
* field. When omitted, no `<target>` is emitted (and nothing is generated
|
|
52
|
+
* unless a description/label is otherwise needed).
|
|
53
|
+
*/
|
|
54
|
+
target?: UIBundleTarget;
|
|
55
|
+
manifestPath?: string;
|
|
56
|
+
bundleName?: string;
|
|
57
|
+
description?: string;
|
|
58
|
+
overwriteExisting?: boolean;
|
|
30
59
|
}
|
|
31
60
|
export interface DiscoveredModule {
|
|
32
61
|
name: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,MAAM,WAAW,QAAQ;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC9C;AAED,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;IAC9B,GAAG,CAAC,EAAE,CAAC,MAAM,GAAG,eAAe,CAAC,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,eAAe;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACpC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,CAAC,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,MAAM,WAAW,QAAQ;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;IAChC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC9C;AAED,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC;IAC9B,GAAG,CAAC,EAAE,CAAC,MAAM,GAAG,eAAe,CAAC,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,eAAe;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACpC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,CAAC,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;CACnD;AAED,MAAM,WAAW,sBAAsB;IACtC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IAExB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,sBAAsB;IACtC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC"}
|
package/docs/consumer-guide.md
CHANGED
|
@@ -259,6 +259,21 @@ export default defineConfig({
|
|
|
259
259
|
});
|
|
260
260
|
```
|
|
261
261
|
|
|
262
|
+
**What is the `providers` array?** It is the list of resolvers for `@salesforce/*`
|
|
263
|
+
scoped-module imports (`@salesforce/label/*`, `@salesforce/i18n/*`,
|
|
264
|
+
`@salesforce/userPermission/*`, `@salesforce/gate/*`, …) that don't exist as
|
|
265
|
+
real npm packages. Each `builtins.*()` returns a Vite plugin that intercepts one
|
|
266
|
+
family of specifiers and generates the module the platform LWC compiler would
|
|
267
|
+
otherwise provide.
|
|
268
|
+
|
|
269
|
+
**You usually don't need it.** When you **omit** `providers` entirely, the plugin
|
|
270
|
+
installs a default set that resolves labels, i18n, permissions, and access checks
|
|
271
|
+
at runtime via GraphQL (see [GraphQL-backed scoped modules](#graphql-backed-scoped-modules-default)
|
|
272
|
+
below). Pass `providers` only to opt a family **out** of the runtime fetch (e.g.
|
|
273
|
+
`builtins.i18n()` for browser/`Intl`-derived locale identity, `builtins.label()`
|
|
274
|
+
for static build-time labels) or to add extra config — the explicit list above
|
|
275
|
+
shows the opt-out shape, not a required one.
|
|
276
|
+
|
|
262
277
|
#### Component Directory Configuration
|
|
263
278
|
|
|
264
279
|
The plugin supports two directory structures:
|
|
@@ -298,8 +313,22 @@ Components are importable as `myNamespace/myComponent`.
|
|
|
298
313
|
|
|
299
314
|
#### Configuring Labels
|
|
300
315
|
|
|
301
|
-
|
|
302
|
-
|
|
316
|
+
There are two providers for `@salesforce/label/*`:
|
|
317
|
+
|
|
318
|
+
- **`builtins.labelsGraphql()` — the default.** Resolves labels at runtime via UI
|
|
319
|
+
API GraphQL through the Platform Data SDK (`createDataSDK()`), so labels reflect
|
|
320
|
+
the current user's translation. The SDK picks the transport per surface: a
|
|
321
|
+
direct session-authenticated GraphQL request in a full-page web app, or the
|
|
322
|
+
`window.openai` bridge in an MCP/ChatGPT host. Build-time values (or the
|
|
323
|
+
key-derived fallback) render until the runtime fetch resolves. Included
|
|
324
|
+
automatically when you omit the `providers` array.
|
|
325
|
+
- **`builtins.label()` — static.** Resolves to a fixed build-time string. Use it
|
|
326
|
+
to opt out of runtime fetching (e.g. a pure off-core demo with no org).
|
|
327
|
+
|
|
328
|
+
Both accept the same overrides object; `labelsGraphql` uses the overrides as the
|
|
329
|
+
static fallback shown before/instead of a successful GraphQL fetch.
|
|
330
|
+
|
|
331
|
+
How you configure labels depends on your project:
|
|
303
332
|
|
|
304
333
|
**SFDX project with `CustomLabels.labels-meta.xml`:**
|
|
305
334
|
|
|
@@ -340,8 +369,95 @@ you'll get runtime errors like:
|
|
|
340
369
|
Uncaught TypeError: Cannot read properties of undefined (reading 'isOpen')
|
|
341
370
|
```
|
|
342
371
|
|
|
343
|
-
|
|
344
|
-
`
|
|
372
|
+
Include `builtins.gate()` when using `lightning-base-components`. (When you omit
|
|
373
|
+
the `providers` array entirely, the default set already covers these.)
|
|
374
|
+
|
|
375
|
+
#### GraphQL-backed scoped modules (default)
|
|
376
|
+
|
|
377
|
+
When you **omit** the `providers` array, these scoped modules resolve at runtime
|
|
378
|
+
via UI API GraphQL through the Platform Data SDK (with build-time first-paint
|
|
379
|
+
values):
|
|
380
|
+
|
|
381
|
+
| Scoped module | GraphQL source (`uiapi.platform.*`) | Provider | First-paint value |
|
|
382
|
+
| -------------------------------------- | ----------------------------------- | ------------------- | ------------------------------------ |
|
|
383
|
+
| `@salesforce/label/*` | `labels` | `labelsGraphql()` | override or key-derived text |
|
|
384
|
+
| `@salesforce/i18n/*` (locale identity) | `i18n` | `platformGraphql()` | CLDR placeholder |
|
|
385
|
+
| `@salesforce/userPermission/*` | `userPermissions` | `platformGraphql()` | **required — you must configure it** |
|
|
386
|
+
| `@salesforce/accessCheck/*` | `userPermissions` | `platformGraphql()` | `false` (deny-by-default) |
|
|
387
|
+
| `@salesforce/customPermission/*` | `customPermissions` | `platformGraphql()` | **required — you must configure it** |
|
|
388
|
+
|
|
389
|
+
The generated modules export the first-paint value as `default` and an opt-in
|
|
390
|
+
`subscribe(callback)` that fires with the resolved org value.
|
|
391
|
+
|
|
392
|
+
##### Named permissions must be configured (no silent guess)
|
|
393
|
+
|
|
394
|
+
A `@salesforce/userPermission/<Name>` or `@salesforce/customPermission/<Name>`
|
|
395
|
+
import is an assertion about **per-user runtime state**. A plain default import
|
|
396
|
+
binds the module's value **once** at module-eval time and never updates on its
|
|
397
|
+
own — so if the plugin silently defaulted an unconfigured permission to `false`,
|
|
398
|
+
your UI would render a permanent, wrong answer about what the current user can do
|
|
399
|
+
(and it would be wrong even on the GraphQL **success** path, because a default
|
|
400
|
+
import never re-reads the resolved value).
|
|
401
|
+
|
|
402
|
+
Rather than guess, **the build fails** if you import a named permission without
|
|
403
|
+
declaring the value it should show before the org responds:
|
|
404
|
+
|
|
405
|
+
```
|
|
406
|
+
[platform-graphql] @salesforce/userPermission/ApiEnabled was imported but has no
|
|
407
|
+
first-paint value configured. …
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Declare it with the `defaultProviders()` helper — which lets you configure this
|
|
411
|
+
one provider while keeping every other default in place:
|
|
412
|
+
|
|
413
|
+
```js
|
|
414
|
+
import lwcVitePlugin, { defaultProviders } from "@salesforce/vite-plugin-lwc-ui-bundle";
|
|
415
|
+
|
|
416
|
+
lwcVitePlugin({
|
|
417
|
+
modules: { dirs: [{ path: "force-app/main/default/lwc", namespace: "c" }] },
|
|
418
|
+
providers: defaultProviders({
|
|
419
|
+
platformGraphql: {
|
|
420
|
+
userPermissionDefaults: { ApiEnabled: false, CustomizeApplication: false },
|
|
421
|
+
customPermissionDefaults: { My_Custom_Perm: false },
|
|
422
|
+
},
|
|
423
|
+
}),
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Use `false` unless you have a specific reason to render `true` before the fetch
|
|
428
|
+
resolves. `@salesforce/accessCheck/*` is exempt: it's a feature **gate**, so an
|
|
429
|
+
unconfigured check safely deny-defaults to `false` (base components rely on this),
|
|
430
|
+
though you can still override it.
|
|
431
|
+
|
|
432
|
+
##### Reflecting the resolved value reactively (`subscribe`)
|
|
433
|
+
|
|
434
|
+
The configured value is only the **first paint**. To show the real org value once
|
|
435
|
+
the GraphQL fetch lands, import the module's `subscribe(callback)` export and
|
|
436
|
+
assign to a reactive field — the callback fires immediately with the current value
|
|
437
|
+
and again when the resolved value differs:
|
|
438
|
+
|
|
439
|
+
```js
|
|
440
|
+
import apiEnabled, { subscribe } from "@salesforce/userPermission/ApiEnabled";
|
|
441
|
+
|
|
442
|
+
export default class extends LightningElement {
|
|
443
|
+
apiEnabled = apiEnabled; // first paint (your configured value)
|
|
444
|
+
connectedCallback() {
|
|
445
|
+
subscribe((v) => (this.apiEnabled = v)); // corrects in the DOM when the org responds
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
> **Dual-deploy note:** the `subscribe` export exists only when the module is
|
|
451
|
+
> served by this plugin. If the **same** component source must also deploy as
|
|
452
|
+
> on-platform LWC metadata (where `@salesforce/userPermission/*` has no `subscribe`
|
|
453
|
+
> export), keep a plain default import — it will render the configured first-paint
|
|
454
|
+
> value off-core and the platform-resolved value on-core.
|
|
455
|
+
|
|
456
|
+
i18n number/date **format** patterns and calendar data stay static (CLDR reference
|
|
457
|
+
data, no org source). `@salesforce/gate/*` also stays static — its GraphQL field is
|
|
458
|
+
UiTier-context-only and not reachable off-core. The static `builtins.i18n()` /
|
|
459
|
+
`builtins.accessCheck()` / `builtins.label()` providers remain available for
|
|
460
|
+
explicit opt-out.
|
|
345
461
|
|
|
346
462
|
### Step 3: Create `index.html`
|
|
347
463
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/vite-plugin-lwc-ui-bundle",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.15.0",
|
|
4
4
|
"description": "Vite plugin for compiling LWC components into static bundles for off-platform and MCP use",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"author": "Salesforce",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"skills"
|
|
50
50
|
],
|
|
51
51
|
"scripts": {
|
|
52
|
-
"build": "vite build && vite build --mode runtime-lds && vite build --mode runtime-labels-graphql",
|
|
52
|
+
"build": "vite build && vite build --mode runtime-lds && vite build --mode runtime-labels-graphql && vite build --mode runtime-platform-graphql",
|
|
53
53
|
"clean": "rm -rf dist",
|
|
54
54
|
"dev": "vite build --watch",
|
|
55
55
|
"test": "vitest run",
|
|
@@ -74,9 +74,9 @@
|
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"@lwc/rollup-plugin": "^9.0.0",
|
|
77
|
-
"@salesforce/platform-sdk": "^11.
|
|
77
|
+
"@salesforce/platform-sdk": "^11.15.0",
|
|
78
78
|
"@salesforce/state-managers-uiapi": "^0.31.0",
|
|
79
|
-
"@salesforce/ui-bundle": "^11.
|
|
79
|
+
"@salesforce/ui-bundle": "^11.15.0",
|
|
80
80
|
"lwc": "^9.0.0",
|
|
81
81
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
|
|
82
82
|
"zod": "^3.23.8"
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"devDependencies": {
|
|
101
101
|
"@conduit-client/bindings-utils": "3.19.6",
|
|
102
102
|
"@conduit-client/command-base": "3.19.6",
|
|
103
|
-
"@salesforce/platform-sdk": "^11.
|
|
103
|
+
"@salesforce/platform-sdk": "^11.15.0",
|
|
104
104
|
"@types/ws": "^8.5.12",
|
|
105
105
|
"typescript": "^5.9.3",
|
|
106
106
|
"vite": "^7.0.0",
|
|
@@ -157,7 +157,15 @@ Starting from the root component, trace the dependency tree:
|
|
|
157
157
|
providers because base components use these modules internally even
|
|
158
158
|
if user code doesn't
|
|
159
159
|
- `@salesforce/gate/*`, `@salesforce/accessCheck/*` → handled by
|
|
160
|
-
those providers
|
|
160
|
+
those providers (accessCheck deny-defaults to `false`, no per-name
|
|
161
|
+
config required)
|
|
162
|
+
- `@salesforce/userPermission/<Name>`, `@salesforce/customPermission/<Name>`
|
|
163
|
+
→ **collect every `<Name>`.** These are named per-user permissions:
|
|
164
|
+
the default `platformGraphql()` provider **fails the build** unless
|
|
165
|
+
each imported name has a first-paint value declared in
|
|
166
|
+
`userPermissionDefaults` / `customPermissionDefaults`. Record the
|
|
167
|
+
exact names so Step 7 can generate them (default them to `false`
|
|
168
|
+
unless the user says otherwise). See `known-pitfalls.md#17`.
|
|
161
169
|
- `@salesforce/i18n/*` → `i18n` provider
|
|
162
170
|
- `@salesforce/client/*` → `client` provider (provides `formFactor`
|
|
163
171
|
based on viewport width)
|
|
@@ -227,6 +235,13 @@ Check in this order:
|
|
|
227
235
|
present (the default registry covers all three specifiers)
|
|
228
236
|
- Step 4 found any `@salesforce/i18n/*` → `builtins.i18n()` must be
|
|
229
237
|
present
|
|
238
|
+
- Step 4 found any `@salesforce/userPermission/<Name>` or
|
|
239
|
+
`@salesforce/customPermission/<Name>` → the default
|
|
240
|
+
`platformGraphql()` provider must declare a first-paint value for
|
|
241
|
+
**each** name in `userPermissionDefaults` / `customPermissionDefaults`,
|
|
242
|
+
or the build throws. Use the `defaultProviders({ platformGraphql: {…} })`
|
|
243
|
+
helper so the rest of the registry stays default. See
|
|
244
|
+
`references/known-pitfalls.md#17`.
|
|
230
245
|
- Step 4 found any `@salesforce/client/*` → `builtins.client()` must
|
|
231
246
|
be present
|
|
232
247
|
- `modules.npm` includes `lightning-base-components` (or
|
|
@@ -465,6 +480,34 @@ Adapt based on earlier findings:
|
|
|
465
480
|
|
|
466
481
|
- Set `dirs` for the detected project structure (SFDX vs namespaced).
|
|
467
482
|
- Populate `builtins.label({...})` with values from Step 6.
|
|
483
|
+
- **Declare a first-paint value for every named permission Step 4 found.**
|
|
484
|
+
Each `@salesforce/userPermission/<Name>` / `@salesforce/customPermission/<Name>`
|
|
485
|
+
import needs an entry, or the build throws (`known-pitfalls.md#17`).
|
|
486
|
+
Prefer the `defaultProviders()` helper so you configure only this while
|
|
487
|
+
keeping the rest of the default registry:
|
|
488
|
+
|
|
489
|
+
```js
|
|
490
|
+
import lwcVitePlugin, { defaultProviders } from "@salesforce/vite-plugin-lwc-ui-bundle";
|
|
491
|
+
|
|
492
|
+
lwcVitePlugin({
|
|
493
|
+
modules: {
|
|
494
|
+
/* ... */
|
|
495
|
+
},
|
|
496
|
+
providers: defaultProviders({
|
|
497
|
+
platformGraphql: {
|
|
498
|
+
userPermissionDefaults: { ApiEnabled: false, CustomizeApplication: false },
|
|
499
|
+
customPermissionDefaults: { My_Custom_Perm: false },
|
|
500
|
+
},
|
|
501
|
+
}),
|
|
502
|
+
});
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
Default each to `false` unless the user wants a `true` first paint; note
|
|
506
|
+
the resolved org value only reaches the DOM if the component imports the
|
|
507
|
+
module's `subscribe()` export (keep a plain default import if the same
|
|
508
|
+
source also deploys on-platform). `@salesforce/accessCheck/*` needs no
|
|
509
|
+
such config — it deny-defaults to `false`.
|
|
510
|
+
|
|
468
511
|
- Include `builtins.primitiveUtils()` if using `lightning-base-components`.
|
|
469
512
|
- Include `builtins.lds()` if any component uses `lightning/uiRecordApi`,
|
|
470
513
|
`lightning/uiObjectInfoApi`, `lightning/graphql`, or any of the
|
|
@@ -440,3 +440,60 @@ the plugin with `livePreview({ debug: true })` (or run with plugin debug
|
|
|
440
440
|
logging) — it logs the underlying import error. Note the bridge is a
|
|
441
441
|
local-dev convenience only; its absence never affects the compiled
|
|
442
442
|
bundle.
|
|
443
|
+
|
|
444
|
+
## 17. Build fails: named permission imported with no first-paint value
|
|
445
|
+
|
|
446
|
+
**Symptom:** `vite build` (or `npm run dev`) fails with:
|
|
447
|
+
|
|
448
|
+
```
|
|
449
|
+
[platform-graphql] @salesforce/userPermission/ApiEnabled was imported but
|
|
450
|
+
has no first-paint value configured. A permission is per-user runtime
|
|
451
|
+
state, so the plugin refuses to silently render a fabricated `false`. …
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Cause:** A component imports `@salesforce/userPermission/<Name>` or
|
|
455
|
+
`@salesforce/customPermission/<Name>`, but no value was declared for that
|
|
456
|
+
name. A named permission is an assertion about **per-user runtime state**;
|
|
457
|
+
a plain default import binds the value **once** at module-eval time and
|
|
458
|
+
never updates on its own (only the module's `subscribe()` export does).
|
|
459
|
+
So a silently-defaulted `false` would render a permanent, wrong answer —
|
|
460
|
+
even when the GraphQL fetch **succeeds**. Rather than guess, the plugin
|
|
461
|
+
requires you to state the value shown before the org responds. (This is
|
|
462
|
+
**not** the same as `@salesforce/accessCheck/*`, which is a feature gate
|
|
463
|
+
and safely deny-defaults to `false` — see pitfall #8.)
|
|
464
|
+
|
|
465
|
+
**Fix:** Declare each imported permission's first-paint value via the
|
|
466
|
+
`defaultProviders()` helper (keeps every other default in place):
|
|
467
|
+
|
|
468
|
+
```js
|
|
469
|
+
import lwcVitePlugin, { defaultProviders } from "@salesforce/vite-plugin-lwc-ui-bundle";
|
|
470
|
+
|
|
471
|
+
lwcVitePlugin({
|
|
472
|
+
modules: {
|
|
473
|
+
/* ... */
|
|
474
|
+
},
|
|
475
|
+
providers: defaultProviders({
|
|
476
|
+
platformGraphql: {
|
|
477
|
+
userPermissionDefaults: { ApiEnabled: false, CustomizeApplication: false },
|
|
478
|
+
customPermissionDefaults: { My_Custom_Perm: false },
|
|
479
|
+
},
|
|
480
|
+
}),
|
|
481
|
+
});
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Use `false` unless you have a specific reason to render `true` before the
|
|
485
|
+
fetch resolves. To reflect the **resolved** org value in the DOM, import
|
|
486
|
+
the module's `subscribe(callback)` export and assign to a reactive field:
|
|
487
|
+
|
|
488
|
+
```js
|
|
489
|
+
import apiEnabled, { subscribe } from "@salesforce/userPermission/ApiEnabled";
|
|
490
|
+
// this.apiEnabled = apiEnabled; // first paint (configured)
|
|
491
|
+
// connectedCallback() { subscribe(v => this.apiEnabled = v); } // corrects in DOM
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
If the same component must also deploy on-platform (where the scoped
|
|
495
|
+
module has no `subscribe` export), keep the plain default import.
|
|
496
|
+
|
|
497
|
+
**Prevention:** SKILL.md Step 4 flags every `@salesforce/userPermission/*`
|
|
498
|
+
and `@salesforce/customPermission/*` import so the generated config
|
|
499
|
+
declares its first-paint value up front.
|