@ethisyscore/vite-plugin 1.141.5 → 1.142.1

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.js CHANGED
@@ -1017,8 +1017,8 @@ var PLATFORM_REACT_EXTERNALS = [
1017
1017
  // Externalised, not bundled, and not merely to save weight: bundling it gave
1018
1018
  // every page its OWN `QueryClient`, so a mutation on the detail page
1019
1019
  // invalidated a cache the list page could not see and a deleted row survived
1020
- // until a browser reload. One host-realm module instance is one cache across
1021
- // every plugin surface.
1020
+ // until a browser reload. One host-realm module instance is one React context,
1021
+ // through which the host hands every surface of a plugin the same client.
1022
1022
  //
1023
1023
  // Requires a host whose `hostModuleRegistry` serves this specifier: an external
1024
1024
  // the deployed host does NOT register is an unresolvable bare import, and the
@@ -1027,25 +1027,26 @@ var PLATFORM_REACT_EXTERNALS = [
1027
1027
  // `useSurfaceQueryClient` in plugin-ui) covers the softer case — module served,
1028
1028
  // no client in scope — and cannot cover this one.
1029
1029
  //
1030
- // THE SECOND GATE, and it binds each plugin rather than the estate: one cache
1031
- // means one KEY SPACE, so two owners using the same key now read each other's
1032
- // entry. Measured across the estate before this change: `["currencies"]` is
1033
- // used verbatim by coreconnect-web, bf-hr and bf-legal, from a copied
1034
- // `useCurrencies.ts` — three owners, one key, previously harmless only because
1035
- // each bundle had a cache of its own.
1036
- //
1037
- // A plugin therefore joins the shared cache the moment it is REBUILT on this
1038
- // SDK, and must have owner-namespaced its keys first. That ordering is the
1039
- // enforcement point and it is per plugin: a plugin not yet rebuilt still has
1040
- // its own cache and is unaffected, so this can be rolled out one plugin at a
1041
- // time rather than estate-wide.
1030
+ // The KEY SPACE is per plugin, and the host owns that boundary. A single
1031
+ // client for the whole app put every plugin's keys beside the host's and each
1032
+ // other's, and they collided: `["employees","lookup"]` is cached by hr,
1033
+ // finance and projects in different shapes, and `["currencies"]` by
1034
+ // coreconnect-web, bf-hr and bf-legal from a copied `useCurrencies.ts`. So the
1035
+ // host (coreconnect-web `pluginQueryClients.ts`, PBI 5626) wraps every page
1036
+ // and overlay of one plugin in a client of that plugin's own: its surfaces
1037
+ // share a cache, and no plugin can read, overwrite or invalidate another's.
1038
+ // Plugin keys need no owner prefix. The corollary is that a plugin cannot
1039
+ // refresh another plugin's cache either; cross-plugin freshness comes from
1040
+ // the kernel's push to each plugin's OWN group (`cache.plugin-invalidate`),
1041
+ // which the host forwards only to the plugin it names and the plugin maps to
1042
+ // its own keys through the definers' `cacheSubscriptions`. The host fans no
1043
+ // plugin's change out to another plugin's client.
1042
1044
  //
1043
1045
  // The ORGANISATION axis needs nothing here, and that was checked rather than
1044
- // assumed: coreconnect-web's AuthContext calls `queryClient.clear()` on logout
1045
- // AND on a live org switch between two non-null tenants, then bumps the
1046
- // authority epoch to force a remount. Plugins sharing that client inherit both.
1047
- // Sharing is in fact stricter than the status quo, where a plugin's private
1048
- // cache is unreachable by the host's teardown.
1046
+ // assumed: coreconnect-web clears its own client AND every plugin client on
1047
+ // logout, on a live organisation or identity switch, and when a plugin's
1048
+ // bundle bytes may have changed, then bumps the authority epoch to force a
1049
+ // remount.
1049
1050
  "@tanstack/react-query"
1050
1051
  ];
1051
1052
  var PLATFORM_REACT_DEDUPE = [
@@ -1127,6 +1128,35 @@ Use a STATIC top-level import of the package root instead. A dynamic import of a
1127
1128
  }
1128
1129
  };
1129
1130
  }
1131
+ var RETIRED_HOST_SPECIFIERS = ["@ethisyscore/host-query-client"];
1132
+ function looksImported(code, spec) {
1133
+ const gap = String.raw`\s*(?:/\*[\s\S]*?\*/\s*)*`;
1134
+ const q = escapeRegExp(spec);
1135
+ return new RegExp(`(?:\\bfrom${gap}|\\bimport${gap}\\(?${gap}|\\brequire${gap}\\(${gap})["'\`]${q}["'\`]`).test(code);
1136
+ }
1137
+ function rejectRetiredHostSpecifiers(retired = RETIRED_HOST_SPECIFIERS) {
1138
+ const retiredSet = new Set(retired);
1139
+ const message = (spec, where) => `[build-pages] ${where} imports "${spec}", which the host keeps registered only so old bundles link: it serves no client a plugin should use. A plugin surface runs on the QueryClient the host provides around it; read it with useQueryClient() inside the surface.`;
1140
+ return {
1141
+ name: "reject-retired-host-specifiers",
1142
+ enforce: "pre",
1143
+ resolveId(source, importer) {
1144
+ if (retiredSet.has(source)) {
1145
+ throw new Error(message(source, importer ?? "a module"));
1146
+ }
1147
+ return null;
1148
+ },
1149
+ renderChunk(code, chunk) {
1150
+ const imported = Array.isArray(chunk.imports) ? /* @__PURE__ */ new Set([...chunk.imports, ...chunk.dynamicImports ?? []]) : void 0;
1151
+ for (const spec of retired) {
1152
+ if (imported ? imported.has(spec) : looksImported(code, spec)) {
1153
+ throw new Error(message(spec, chunk.fileName ?? "bundle"));
1154
+ }
1155
+ }
1156
+ return null;
1157
+ }
1158
+ };
1159
+ }
1130
1160
  function virtualPageEntry(page, config) {
1131
1161
  const VIRTUAL_ID = `\0virtual:surface/${page.id}`;
1132
1162
  const views = page.views ?? {};
@@ -1212,6 +1242,8 @@ function makeDefaultBuild(viteBuild) {
1212
1242
  // `enforce: "pre"`, this one declares none. See its doc for why "none" is the
1213
1243
  // only position that sees compiled CSS.
1214
1244
  plugins: [
1245
+ // First, so a retired host specifier fails with its importer's name before anything resolves it.
1246
+ rejectRetiredHostSpecifiers(),
1215
1247
  ctx.surfacePlugin,
1216
1248
  ...ctx.plugins,
1217
1249
  scopePluginCssPlugin(),
@@ -1452,7 +1484,8 @@ function ethisysPlatformReactPlugin(options = {}) {
1452
1484
  return [
1453
1485
  ethisysPlatformReactPagesPlugin(options),
1454
1486
  scopePluginCssPlugin(),
1455
- assertHostResolvableExternals([...PLATFORM_REACT_EXTERNALS, "@ethisyscore/host-ui-externals"])
1487
+ assertHostResolvableExternals([...PLATFORM_REACT_EXTERNALS, "@ethisyscore/host-ui-externals"]),
1488
+ rejectRetiredHostSpecifiers()
1456
1489
  ];
1457
1490
  }
1458
1491
  function ethisysPlatformReactPagesPlugin(options = {}) {