@wordrhyme/plugin 0.1.0-alpha.5 → 0.1.0-alpha.7

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 (41) hide show
  1. package/dist/artifact.d.ts +1 -1
  2. package/dist/artifact.js +2 -1
  3. package/dist/artifact.js.map +1 -1
  4. package/dist/chunk-BI7E5CVM.js +26 -0
  5. package/dist/chunk-BI7E5CVM.js.map +1 -0
  6. package/dist/{chunk-46KUIGB6.js → chunk-BVOTSKM2.js} +36 -12
  7. package/dist/chunk-BVOTSKM2.js.map +1 -0
  8. package/dist/{chunk-QNCOGISF.js → chunk-FOCLZY64.js} +114 -3
  9. package/dist/chunk-FOCLZY64.js.map +1 -0
  10. package/dist/{chunk-YQDKOEUI.js → chunk-NAWUXVZQ.js} +43 -15
  11. package/dist/chunk-NAWUXVZQ.js.map +1 -0
  12. package/dist/{chunk-ZUBFLOKU.js → chunk-O4AYK3YP.js} +5 -2
  13. package/dist/chunk-O4AYK3YP.js.map +1 -0
  14. package/dist/{client-WXWbuuvd.d.ts → client-CKtDWayV.d.ts} +1 -1
  15. package/dist/client.d.ts +2 -2
  16. package/dist/client.js +2 -1
  17. package/dist/dev-utils.d.ts +6 -2
  18. package/dist/dev-utils.js +3 -1
  19. package/dist/{entity-extensions-B5BbZH-m.d.ts → entity-extensions-gJuSTXYZ.d.ts} +2 -2
  20. package/dist/globalization.d.ts +7 -2
  21. package/dist/globalization.js +11 -1
  22. package/dist/index.d.ts +381 -8
  23. package/dist/index.js +449 -18
  24. package/dist/index.js.map +1 -1
  25. package/dist/locale.d.ts +15 -0
  26. package/dist/locale.js +13 -0
  27. package/dist/locale.js.map +1 -0
  28. package/dist/{manifest-CPSCN_Ft.d.ts → manifest-CDTCsMYV.d.ts} +39 -4
  29. package/dist/react.d.ts +50 -3
  30. package/dist/react.js +105 -11
  31. package/dist/react.js.map +1 -1
  32. package/dist/server.d.ts +5 -4
  33. package/dist/server.js +1 -1
  34. package/dist/trpc.d.ts +2 -1
  35. package/dist/trpc.js +1 -1
  36. package/dist/{types-8P7XyoyQ.d.ts → types-9v-WZ_NU.d.ts} +230 -1
  37. package/package.json +10 -1
  38. package/dist/chunk-46KUIGB6.js.map +0 -1
  39. package/dist/chunk-QNCOGISF.js.map +0 -1
  40. package/dist/chunk-YQDKOEUI.js.map +0 -1
  41. package/dist/chunk-ZUBFLOKU.js.map +0 -1
@@ -233,7 +233,16 @@ declare const adminTourSchema: z.ZodObject<{
233
233
  }, z.core.$strip>>;
234
234
  }, z.core.$strip>;
235
235
  type AdminTour = z.infer<typeof adminTourSchema>;
236
- declare const pluginI18nSchema: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>>;
236
+ declare const pluginI18nSchema: z.ZodUnion<readonly [z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>>, z.ZodTransform<Record<string, Record<string, string>>, Record<string, Record<string, string>>>>, z.ZodObject<{
237
+ namespace: z.ZodOptional<z.ZodString>;
238
+ messages: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodString>, z.ZodTransform<Record<string, string>, Record<string, string>>>>>;
239
+ localesFile: z.ZodOptional<z.ZodString>;
240
+ onUninstall: z.ZodOptional<z.ZodEnum<{
241
+ delete: "delete";
242
+ archive: "archive";
243
+ retain: "retain";
244
+ }>>;
245
+ }, z.core.$strict>]>;
237
246
  declare const entityExtensionFieldTypeSchema: z.ZodEnum<{
238
247
  number: "number";
239
248
  boolean: "boolean";
@@ -977,7 +986,16 @@ declare const pluginManifestSchema: z.ZodObject<{
977
986
  integration: "integration";
978
987
  feature: "feature";
979
988
  }>>;
980
- i18n: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>>>;
989
+ i18n: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>>, z.ZodTransform<Record<string, Record<string, string>>, Record<string, Record<string, string>>>>, z.ZodObject<{
990
+ namespace: z.ZodOptional<z.ZodString>;
991
+ messages: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodString>, z.ZodTransform<Record<string, string>, Record<string, string>>>>>;
992
+ localesFile: z.ZodOptional<z.ZodString>;
993
+ onUninstall: z.ZodOptional<z.ZodEnum<{
994
+ delete: "delete";
995
+ archive: "archive";
996
+ retain: "retain";
997
+ }>>;
998
+ }, z.core.$strict>]>>;
981
999
  runtime: z.ZodDefault<z.ZodEnum<{
982
1000
  node: "node";
983
1001
  }>>;
@@ -999,6 +1017,23 @@ declare const pluginManifestSchema: z.ZodObject<{
999
1017
  artifacts: z.ZodOptional<z.ZodObject<{
1000
1018
  write: z.ZodOptional<z.ZodBoolean>;
1001
1019
  }, z.core.$strip>>;
1020
+ agent: z.ZodOptional<z.ZodObject<{
1021
+ runtime: z.ZodOptional<z.ZodBoolean>;
1022
+ invoker: z.ZodOptional<z.ZodBoolean>;
1023
+ tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
1024
+ id: z.ZodString;
1025
+ title: z.ZodString;
1026
+ summary: z.ZodOptional<z.ZodString>;
1027
+ }, z.core.$strip>>>;
1028
+ }, z.core.$strip>>;
1029
+ ai: z.ZodOptional<z.ZodObject<{
1030
+ aliases: z.ZodOptional<z.ZodArray<z.ZodObject<{
1031
+ id: z.ZodString;
1032
+ name: z.ZodString;
1033
+ description: z.ZodOptional<z.ZodString>;
1034
+ }, z.core.$strip>>>;
1035
+ provider: z.ZodOptional<z.ZodBoolean>;
1036
+ }, z.core.$strip>>;
1002
1037
  provides: z.ZodOptional<z.ZodArray<z.ZodString>>;
1003
1038
  billing: z.ZodOptional<z.ZodObject<{
1004
1039
  subjects: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -1057,10 +1092,10 @@ declare const pluginManifestSchema: z.ZodObject<{
1057
1092
  paths: z.ZodArray<z.ZodString>;
1058
1093
  }, z.core.$strip>>;
1059
1094
  hooks: z.ZodOptional<z.ZodArray<z.ZodEnum<{
1095
+ onUninstall: "onUninstall";
1060
1096
  onInstall: "onInstall";
1061
1097
  onEnable: "onEnable";
1062
1098
  onDisable: "onDisable";
1063
- onUninstall: "onUninstall";
1064
1099
  }>>>;
1065
1100
  }, z.core.$strip>>;
1066
1101
  admin: z.ZodOptional<z.ZodObject<{
@@ -1379,9 +1414,9 @@ declare const pluginManifestSchema: z.ZodObject<{
1379
1414
  retain: "retain";
1380
1415
  }>>;
1381
1416
  onUninstall: z.ZodOptional<z.ZodEnum<{
1382
- retain: "retain";
1383
1417
  delete: "delete";
1384
1418
  archive: "archive";
1419
+ retain: "retain";
1385
1420
  }>>;
1386
1421
  tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
1387
1422
  }, z.core.$strip>>;
package/dist/react.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
- import { P as PluginMediaInfo } from './types-8P7XyoyQ.js';
3
- import './globalization.js';
2
+ import { CurrencyInfo, FormatPriceOptions } from './globalization.js';
3
+ import { P as PluginMediaInfo } from './types-9v-WZ_NU.js';
4
4
  import 'decimal.js';
5
+ import './locale.js';
5
6
  import './release-CyapqJ3z.js';
6
7
  import 'zod';
7
8
  import './time.js';
@@ -44,20 +45,49 @@ declare function usePluginTrpc(pluginId: string): any;
44
45
  */
45
46
  declare function useHostTrpc(): any;
46
47
  interface PluginI18nValue {
48
+ pluginId?: string | undefined;
49
+ namespace?: string | undefined;
47
50
  locale: string;
48
51
  timezone: string;
49
52
  isLoading: boolean;
53
+ availableLocales: readonly string[];
54
+ languages: readonly PluginLanguageOption[];
50
55
  t: (key: string, paramsOrDefault?: Record<string, string | number> | string) => string;
56
+ /** Host-bound Core common translator. Optional for compatibility with older Hosts. */
57
+ tCommon?: (key: string, paramsOrDefault?: Record<string, string | number> | string) => string;
51
58
  addNamespace: (namespace: string) => void;
52
59
  }
60
+ interface PluginLanguageOption {
61
+ locale: string;
62
+ name: string;
63
+ nativeName: string;
64
+ direction: 'ltr' | 'rtl';
65
+ isDefault: boolean;
66
+ sortOrder: number;
67
+ }
53
68
  declare const PluginI18nContext: React.Context<PluginI18nValue>;
54
69
  declare function usePluginTranslation(pluginId: string, customNamespace?: string): {
55
70
  t: (key: string, paramsOrDefault?: Record<string, string | number> | string) => string;
71
+ tCommon: (key: string, paramsOrDefault?: Record<string, string | number> | string) => string;
56
72
  locale: string;
57
73
  timezone: string;
58
74
  isLoading: boolean;
75
+ availableLocales: readonly string[];
76
+ languages: readonly PluginLanguageOption[];
59
77
  namespace: string;
60
78
  };
79
+ /** Currency capabilities exposed by the Admin Host to plugin UIs. */
80
+ interface PluginCurrencyValue {
81
+ currency: CurrencyInfo;
82
+ currencies: CurrencyInfo[];
83
+ baseCurrency: CurrencyInfo;
84
+ isLoading: boolean;
85
+ isReady: boolean;
86
+ changeCurrency: (currencyCode: string) => void;
87
+ formatPrice: (cents: number, fromCurrency?: string | undefined, options?: FormatPriceOptions | undefined) => string;
88
+ }
89
+ declare const PluginCurrencyContext: React.Context<PluginCurrencyValue>;
90
+ declare function usePluginCurrency(): PluginCurrencyValue;
61
91
  interface PluginSlotProps {
62
92
  /** Slot name, e.g. 'shop.product.detail.actions' */
63
93
  name: string;
@@ -72,12 +102,29 @@ interface PluginSlotProps {
72
102
  /** Fallback when no extensions registered */
73
103
  fallback?: React.ReactNode;
74
104
  }
105
+ interface PluginSlotRegistry {
106
+ /** Returns whether at least one extension is registered for the slot. */
107
+ has: (name: string) => boolean;
108
+ /** Subscribes to extension registry changes. */
109
+ subscribe: (onStoreChange: () => void) => () => void;
110
+ }
75
111
  /**
76
112
  * Called by the Admin Host at startup to inject the PluginSlot component.
77
113
  * Plugin code should NOT call this directly.
78
114
  * @internal
79
115
  */
80
116
  declare function __setPluginSlot(component: React.ComponentType<PluginSlotProps>): void;
117
+ /**
118
+ * Called by the Admin Host at startup to expose reactive slot availability.
119
+ * Plugin code should NOT call this directly.
120
+ * @internal
121
+ */
122
+ declare function __setPluginSlotRegistry(registry: PluginSlotRegistry | null): void;
123
+ /**
124
+ * Returns whether the given slot currently has at least one registered extension.
125
+ * The value updates when plugins are registered, reloaded, disabled, or removed.
126
+ */
127
+ declare function usePluginSlot(name: string): boolean;
81
128
  /**
82
129
  * Renders all plugin extensions registered for the given slot.
83
130
  *
@@ -142,4 +189,4 @@ declare function useMediaPicker(): {
142
189
  openDialog: (options: MediaPickerOptions) => void;
143
190
  };
144
191
 
145
- export { type MediaPickerOptions, type PluginAbility, PluginAbilityContext, PluginI18nContext, type PluginI18nValue, PluginSlot, type PluginSlotProps, __setPluginSlot, __setTrpc, useHostTrpc, useMediaPicker, usePluginAbility, usePluginTranslation, usePluginTrpc };
192
+ export { type MediaPickerOptions, type PluginAbility, PluginAbilityContext, PluginCurrencyContext, type PluginCurrencyValue, PluginI18nContext, type PluginI18nValue, type PluginLanguageOption, PluginSlot, type PluginSlotProps, type PluginSlotRegistry, __setPluginSlot, __setPluginSlotRegistry, __setTrpc, useHostTrpc, useMediaPicker, usePluginAbility, usePluginCurrency, usePluginSlot, usePluginTranslation, usePluginTrpc };
package/dist/react.js CHANGED
@@ -1,8 +1,15 @@
1
+ import {
2
+ DEFAULT_CURRENCY
3
+ } from "./chunk-BVOTSKM2.js";
4
+ import "./chunk-BI7E5CVM.js";
5
+
1
6
  // src/react.ts
2
7
  import React from "react";
3
8
  var _trpc = null;
9
+ var _hostTrpcFacade = null;
4
10
  function __setTrpc(trpc) {
5
11
  _trpc = trpc;
12
+ _hostTrpcFacade = null;
6
13
  }
7
14
  function usePluginTrpc(pluginId) {
8
15
  if (!_trpc) {
@@ -19,13 +26,35 @@ function useHostTrpc() {
19
26
  "[plugin/react] tRPC not initialized. Ensure plugin is loaded within Admin Host context."
20
27
  );
21
28
  }
22
- return _trpc;
29
+ if (!_hostTrpcFacade) {
30
+ _hostTrpcFacade = new Proxy(_trpc, {
31
+ get(target, property, receiver) {
32
+ if (property === "i18n") {
33
+ throw new Error(
34
+ "[plugin/react] Host i18n APIs are not exposed to plugins. Use the Host-bound usePluginTranslation() bridge."
35
+ );
36
+ }
37
+ return Reflect.get(target, property, receiver);
38
+ },
39
+ has(target, property) {
40
+ return property === "i18n" ? false : Reflect.has(target, property);
41
+ },
42
+ ownKeys(target) {
43
+ return Reflect.ownKeys(target).filter((property) => property !== "i18n");
44
+ }
45
+ });
46
+ }
47
+ return _hostTrpcFacade;
23
48
  }
49
+ var fallbackPluginTranslate = (key, paramsOrDefault) => typeof paramsOrDefault === "string" ? paramsOrDefault : key;
24
50
  var defaultI18n = {
25
51
  locale: "en-US",
26
52
  timezone: "UTC",
27
53
  isLoading: false,
28
- t: (key, paramsOrDefault) => typeof paramsOrDefault === "string" ? paramsOrDefault : key,
54
+ availableLocales: [],
55
+ languages: [],
56
+ t: fallbackPluginTranslate,
57
+ tCommon: fallbackPluginTranslate,
29
58
  addNamespace: () => void 0
30
59
  };
31
60
  var PluginI18nContext = React.createContext(defaultI18n);
@@ -33,27 +62,88 @@ function normalizePluginNamespace(pluginId) {
33
62
  return `plugin.${pluginId}`;
34
63
  }
35
64
  function usePluginTranslation(pluginId, customNamespace) {
36
- const namespace = customNamespace || normalizePluginNamespace(pluginId);
37
65
  const i18n = React.useContext(PluginI18nContext);
38
- React.useEffect(() => {
39
- i18n.addNamespace(namespace);
40
- }, [i18n, namespace]);
66
+ if (!i18n.pluginId || !i18n.namespace) {
67
+ throw new Error("[plugin/react] Plugin i18n boundary is missing");
68
+ }
69
+ if (pluginId !== i18n.pluginId) {
70
+ throw new Error(
71
+ `[plugin/react] Plugin i18n identity mismatch: expected ${i18n.pluginId}, received ${pluginId}`
72
+ );
73
+ }
74
+ const namespace = normalizePluginNamespace(pluginId);
75
+ if (customNamespace && customNamespace !== namespace) {
76
+ throw new Error(
77
+ `[plugin/react] Plugin namespace mismatch: expected ${namespace}, received ${customNamespace}`
78
+ );
79
+ }
80
+ if (i18n.namespace !== namespace) {
81
+ throw new Error(
82
+ `[plugin/react] Host-bound namespace mismatch: expected ${namespace}, received ${i18n.namespace}`
83
+ );
84
+ }
41
85
  const t = React.useCallback(
42
86
  (key, paramsOrDefault) => {
43
- const fullKey = key.startsWith(`${namespace}.`) ? key : `${namespace}.${key}`;
44
- return i18n.t(fullKey, paramsOrDefault);
87
+ const prefix = `${namespace}.`;
88
+ const localKey = key.startsWith(prefix) ? key.slice(prefix.length) : key;
89
+ return i18n.t(localKey, paramsOrDefault);
45
90
  },
46
- [i18n, namespace]
91
+ [i18n]
47
92
  );
93
+ const tCommon = i18n.tCommon ?? fallbackPluginTranslate;
48
94
  return React.useMemo(
49
- () => ({ t, locale: i18n.locale, timezone: i18n.timezone, isLoading: i18n.isLoading, namespace }),
50
- [t, i18n.locale, i18n.timezone, i18n.isLoading, namespace]
95
+ () => ({
96
+ t,
97
+ tCommon,
98
+ locale: i18n.locale,
99
+ timezone: i18n.timezone,
100
+ isLoading: i18n.isLoading,
101
+ availableLocales: i18n.availableLocales,
102
+ languages: i18n.languages,
103
+ namespace
104
+ }),
105
+ [
106
+ t,
107
+ tCommon,
108
+ i18n.locale,
109
+ i18n.timezone,
110
+ i18n.isLoading,
111
+ i18n.availableLocales,
112
+ i18n.languages,
113
+ namespace
114
+ ]
51
115
  );
52
116
  }
117
+ var defaultPluginCurrency = {
118
+ currency: DEFAULT_CURRENCY,
119
+ currencies: [],
120
+ baseCurrency: DEFAULT_CURRENCY,
121
+ isLoading: false,
122
+ isReady: false,
123
+ changeCurrency: () => void 0,
124
+ formatPrice: (cents, fromCurrency) => `${fromCurrency ?? DEFAULT_CURRENCY.code} ${(cents / 100).toFixed(2)}`
125
+ };
126
+ var PluginCurrencyContext = React.createContext(defaultPluginCurrency);
127
+ function usePluginCurrency() {
128
+ return React.useContext(PluginCurrencyContext);
129
+ }
53
130
  var _PluginSlotImpl = null;
131
+ var _pluginSlotRegistry = null;
132
+ var emptyPluginSlotSubscribe = () => () => void 0;
54
133
  function __setPluginSlot(component) {
55
134
  _PluginSlotImpl = component;
56
135
  }
136
+ function __setPluginSlotRegistry(registry) {
137
+ _pluginSlotRegistry = registry;
138
+ }
139
+ function usePluginSlot(name) {
140
+ const getSnapshot = () => _pluginSlotRegistry?.has(name) ?? false;
141
+ return React.useSyncExternalStore(
142
+ _pluginSlotRegistry?.subscribe ?? emptyPluginSlotSubscribe,
143
+ getSnapshot,
144
+ getSnapshot
145
+ );
146
+ }
57
147
  function PluginSlot(props) {
58
148
  if (!_PluginSlotImpl) {
59
149
  return null;
@@ -81,13 +171,17 @@ function useMediaPicker() {
81
171
  }
82
172
  export {
83
173
  PluginAbilityContext,
174
+ PluginCurrencyContext,
84
175
  PluginI18nContext,
85
176
  PluginSlot,
86
177
  __setPluginSlot,
178
+ __setPluginSlotRegistry,
87
179
  __setTrpc,
88
180
  useHostTrpc,
89
181
  useMediaPicker,
90
182
  usePluginAbility,
183
+ usePluginCurrency,
184
+ usePluginSlot,
91
185
  usePluginTranslation,
92
186
  usePluginTrpc
93
187
  };
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.ts"],"sourcesContent":["/**\n * React utilities for plugin admin UIs.\n *\n * At runtime, this module is shared via Module Federation from the admin host.\n * Plugins should configure MF shared with `import: false` for this package.\n */\nimport React from 'react';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _trpc: any = null;\n\n/**\n * Called by the Admin Host at startup to inject the host's tRPC React client.\n * Plugin code should NOT call this directly.\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function __setTrpc(trpc: any) {\n _trpc = trpc;\n}\n\n/**\n * Hook for plugin components to access their tRPC namespace with React Query hooks.\n * Must be called within a component rendered inside the Admin Host.\n *\n * @param pluginId - Short plugin ID (e.g., 'storage-s3') or full ID (e.g., 'com.wordrhyme.storage-s3')\n * @returns tRPC proxy with useQuery/useMutation hooks\n *\n * @example\n * ```tsx\n * import { usePluginTrpc } from '@wordrhyme/plugin/react';\n *\n * function MyPluginPage() {\n * const api = usePluginTrpc('my-plugin');\n * const { data, isLoading } = api.listItems.useQuery();\n * const createItem = api.createItem.useMutation();\n * }\n * ```\n */\nexport function usePluginTrpc(pluginId: string) {\n if (!_trpc) {\n throw new Error(\n '[plugin/react] tRPC not initialized. ' +\n 'Ensure plugin is loaded within Admin Host context.',\n );\n }\n const normalizedId = pluginId\n .replace(/^com\\.wordrhyme\\./, '')\n .replace(/\\./g, '-');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (_trpc as any).pluginApis[normalizedId];\n}\n\n/**\n * Hook for plugin components to access the Admin Host's root tRPC React client.\n * Useful for shared host capabilities such as currency, media, auth, etc.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function useHostTrpc(): any {\n if (!_trpc) {\n throw new Error(\n '[plugin/react] tRPC not initialized. ' +\n 'Ensure plugin is loaded within Admin Host context.',\n );\n }\n return _trpc;\n}\n\n// ============================================================\n// I18n — host translation bridge\n// ============================================================\n\nexport interface PluginI18nValue {\n locale: string;\n timezone: string;\n isLoading: boolean;\n t: (key: string, paramsOrDefault?: Record<string, string | number> | string) => string;\n addNamespace: (namespace: string) => void;\n}\n\nconst defaultI18n: PluginI18nValue = {\n locale: 'en-US',\n timezone: 'UTC',\n isLoading: false,\n t: (key, paramsOrDefault) => (typeof paramsOrDefault === 'string' ? paramsOrDefault : key),\n addNamespace: () => undefined,\n};\n\nexport const PluginI18nContext = React.createContext<PluginI18nValue>(defaultI18n);\n\nfunction normalizePluginNamespace(pluginId: string): string {\n return `plugin.${pluginId}`;\n}\n\nexport function usePluginTranslation(pluginId: string, customNamespace?: string) {\n const namespace = customNamespace || normalizePluginNamespace(pluginId);\n const i18n = React.useContext(PluginI18nContext);\n\n React.useEffect(() => {\n i18n.addNamespace(namespace);\n }, [i18n, namespace]);\n\n const t = React.useCallback(\n (key: string, paramsOrDefault?: Record<string, string | number> | string): string => {\n const fullKey = key.startsWith(`${namespace}.`) ? key : `${namespace}.${key}`;\n return i18n.t(fullKey, paramsOrDefault);\n },\n [i18n, namespace],\n );\n\n return React.useMemo(\n () => ({ t, locale: i18n.locale, timezone: i18n.timezone, isLoading: i18n.isLoading, namespace }),\n [t, i18n.locale, i18n.timezone, i18n.isLoading, namespace],\n );\n}\n\n// ============================================================\n// PluginSlot — runtime-injected from Admin Host\n// ============================================================\n\nexport interface PluginSlotProps {\n /** Slot name, e.g. 'shop.product.detail.actions' */\n name: string;\n /** React props passed to extensions rendered in this slot */\n props?: Record<string, unknown>;\n /** @deprecated Use props. Kept for legacy plugin slot call sites. */\n context?: Record<string, unknown>;\n /** Layout mode */\n layout?: 'inline' | 'stack' | 'tabs' | 'grid';\n /** Additional CSS class */\n className?: string;\n /** Fallback when no extensions registered */\n fallback?: React.ReactNode;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _PluginSlotImpl: React.ComponentType<PluginSlotProps> | null = null;\n\n/**\n * Called by the Admin Host at startup to inject the PluginSlot component.\n * Plugin code should NOT call this directly.\n * @internal\n */\nexport function __setPluginSlot(component: React.ComponentType<PluginSlotProps>) {\n _PluginSlotImpl = component;\n}\n\n/**\n * Renders all plugin extensions registered for the given slot.\n *\n * @example\n * ```tsx\n * import { PluginSlot } from '@wordrhyme/plugin/react';\n *\n * function ProductDetailPage({ productId }) {\n * return (\n * <div>\n * <h1>Product Detail</h1>\n * <PluginSlot\n * name=\"shop.product.detail.actions\"\n * layout=\"inline\"\n * props={{ productId }}\n * />\n * </div>\n * );\n * }\n * ```\n */\nexport function PluginSlot(props: PluginSlotProps): React.ReactElement | null {\n if (!_PluginSlotImpl) {\n // Silently render nothing if host hasn't injected yet\n return null;\n }\n return React.createElement(_PluginSlotImpl, props);\n}\n\n// Ability — runtime-injected from Admin Host (CASL permission)\n// ============================================================\n\n/**\n * Minimal ability interface for plugin permission checks.\n * Matches CASL MongoAbility.can() signature.\n */\nexport interface PluginAbility {\n can(action: string, subject: string): boolean;\n}\n\n/** Default allow-all ability (when host hasn't injected) */\nconst defaultAbility: PluginAbility = { can: () => true };\n\n/**\n * React Context for ability — shared between host and plugins.\n * Host injects via AbilityBridge, plugins consume via usePluginAbility.\n */\nexport const PluginAbilityContext = React.createContext<PluginAbility>(defaultAbility);\n\n/**\n * Hook for plugin components to check permissions.\n *\n * @example\n * ```tsx\n * import { usePluginAbility } from '@wordrhyme/plugin/react';\n *\n * function MyPluginPage() {\n * const ability = usePluginAbility();\n * const canCreate = ability.can('create', 'PluginResource');\n * const canDelete = ability.can('delete', 'PluginResource');\n * }\n * ```\n */\nexport function usePluginAbility(): PluginAbility {\n return React.useContext(PluginAbilityContext);\n}\n\n// ============================================================\n// Media Picker — accesses global imperative API\n// ============================================================\n\nimport type { PluginMediaInfo } from './types';\n\n// Define the options for the global MediaPicker\nexport interface MediaPickerOptions {\n presentation?: 'dialog' | 'drawer'; // Where to open the picker\n mode?: 'single' | 'multi';\n category?: 'all' | 'image' | 'document' | 'video' | 'audio' | 'archive' | 'other';\n onSelect: (media: PluginMediaInfo[]) => void;\n}\n\n/**\n * Hook to open the global Media Picker dialog (rendered by Admin Host).\n * Returns an imperative API `openDialog(options)`.\n */\nexport function useMediaPicker() {\n return {\n openDialog: (options: MediaPickerOptions) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n if (typeof window !== 'undefined') {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n const picker = window.__WORDRHYME_MEDIA_PICKER__ || window.__OMNIDS_MEDIA_PICKER__;\n if (picker) {\n picker.open(options);\n return;\n }\n }\n console.warn('[plugin/react] Media Picker is not mounted by the Admin Host.');\n }\n };\n}\n"],"mappings":";AAMA,OAAO,WAAW;AAGlB,IAAI,QAAa;AAQV,SAAS,UAAU,MAAW;AACjC,UAAQ;AACZ;AAoBO,SAAS,cAAc,UAAkB;AAC5C,MAAI,CAAC,OAAO;AACR,UAAM,IAAI;AAAA,MACN;AAAA,IAEJ;AAAA,EACJ;AACA,QAAM,eAAe,SAChB,QAAQ,qBAAqB,EAAE,EAC/B,QAAQ,OAAO,GAAG;AAEvB,SAAQ,MAAc,WAAW,YAAY;AACjD;AAOO,SAAS,cAAmB;AAC/B,MAAI,CAAC,OAAO;AACR,UAAM,IAAI;AAAA,MACN;AAAA,IAEJ;AAAA,EACJ;AACA,SAAO;AACX;AAcA,IAAM,cAA+B;AAAA,EACjC,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,WAAW;AAAA,EACX,GAAG,CAAC,KAAK,oBAAqB,OAAO,oBAAoB,WAAW,kBAAkB;AAAA,EACtF,cAAc,MAAM;AACxB;AAEO,IAAM,oBAAoB,MAAM,cAA+B,WAAW;AAEjF,SAAS,yBAAyB,UAA0B;AACxD,SAAO,UAAU,QAAQ;AAC7B;AAEO,SAAS,qBAAqB,UAAkB,iBAA0B;AAC7E,QAAM,YAAY,mBAAmB,yBAAyB,QAAQ;AACtE,QAAM,OAAO,MAAM,WAAW,iBAAiB;AAE/C,QAAM,UAAU,MAAM;AAClB,SAAK,aAAa,SAAS;AAAA,EAC/B,GAAG,CAAC,MAAM,SAAS,CAAC;AAEpB,QAAM,IAAI,MAAM;AAAA,IACZ,CAAC,KAAa,oBAAuE;AACjF,YAAM,UAAU,IAAI,WAAW,GAAG,SAAS,GAAG,IAAI,MAAM,GAAG,SAAS,IAAI,GAAG;AAC3E,aAAO,KAAK,EAAE,SAAS,eAAe;AAAA,IAC1C;AAAA,IACA,CAAC,MAAM,SAAS;AAAA,EACpB;AAEA,SAAO,MAAM;AAAA,IACT,OAAO,EAAE,GAAG,QAAQ,KAAK,QAAQ,UAAU,KAAK,UAAU,WAAW,KAAK,WAAW,UAAU;AAAA,IAC/F,CAAC,GAAG,KAAK,QAAQ,KAAK,UAAU,KAAK,WAAW,SAAS;AAAA,EAC7D;AACJ;AAsBA,IAAI,kBAA+D;AAO5D,SAAS,gBAAgB,WAAiD;AAC7E,oBAAkB;AACtB;AAuBO,SAAS,WAAW,OAAmD;AAC1E,MAAI,CAAC,iBAAiB;AAElB,WAAO;AAAA,EACX;AACA,SAAO,MAAM,cAAc,iBAAiB,KAAK;AACrD;AAcA,IAAM,iBAAgC,EAAE,KAAK,MAAM,KAAK;AAMjD,IAAM,uBAAuB,MAAM,cAA6B,cAAc;AAgB9E,SAAS,mBAAkC;AAC9C,SAAO,MAAM,WAAW,oBAAoB;AAChD;AAoBO,SAAS,iBAAiB;AAC7B,SAAO;AAAA,IACH,YAAY,CAAC,YAAgC;AAGzC,UAAI,OAAO,WAAW,aAAa;AAG/B,cAAM,SAAS,OAAO,8BAA8B,OAAO;AAC3D,YAAI,QAAQ;AACR,iBAAO,KAAK,OAAO;AACnB;AAAA,QACJ;AAAA,MACJ;AACA,cAAQ,KAAK,+DAA+D;AAAA,IAChF;AAAA,EACJ;AACJ;","names":[]}
1
+ {"version":3,"sources":["../src/react.ts"],"sourcesContent":["/**\n * React utilities for plugin admin UIs.\n *\n * At runtime, this module is shared via Module Federation from the admin host.\n * Plugins should configure MF shared with `import: false` for this package.\n */\nimport React from 'react';\nimport {\n DEFAULT_CURRENCY,\n type CurrencyInfo,\n type FormatPriceOptions,\n} from './globalization';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _trpc: any = null;\nlet _hostTrpcFacade: any = null;\n\n/**\n * Called by the Admin Host at startup to inject the host's tRPC React client.\n * Plugin code should NOT call this directly.\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function __setTrpc(trpc: any) {\n _trpc = trpc;\n _hostTrpcFacade = null;\n}\n\n/**\n * Hook for plugin components to access their tRPC namespace with React Query hooks.\n * Must be called within a component rendered inside the Admin Host.\n *\n * @param pluginId - Short plugin ID (e.g., 'storage-s3') or full ID (e.g., 'com.wordrhyme.storage-s3')\n * @returns tRPC proxy with useQuery/useMutation hooks\n *\n * @example\n * ```tsx\n * import { usePluginTrpc } from '@wordrhyme/plugin/react';\n *\n * function MyPluginPage() {\n * const api = usePluginTrpc('my-plugin');\n * const { data, isLoading } = api.listItems.useQuery();\n * const createItem = api.createItem.useMutation();\n * }\n * ```\n */\nexport function usePluginTrpc(pluginId: string) {\n if (!_trpc) {\n throw new Error(\n '[plugin/react] tRPC not initialized. ' +\n 'Ensure plugin is loaded within Admin Host context.',\n );\n }\n const normalizedId = pluginId\n .replace(/^com\\.wordrhyme\\./, '')\n .replace(/\\./g, '-');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (_trpc as any).pluginApis[normalizedId];\n}\n\n/**\n * Hook for plugin components to access the Admin Host's root tRPC React client.\n * Useful for shared host capabilities such as currency, media, auth, etc.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function useHostTrpc(): any {\n if (!_trpc) {\n throw new Error(\n '[plugin/react] tRPC not initialized. ' +\n 'Ensure plugin is loaded within Admin Host context.',\n );\n }\n if (!_hostTrpcFacade) {\n _hostTrpcFacade = new Proxy(_trpc, {\n get(target, property, receiver) {\n if (property === 'i18n') {\n throw new Error(\n '[plugin/react] Host i18n APIs are not exposed to plugins. ' +\n 'Use the Host-bound usePluginTranslation() bridge.',\n );\n }\n return Reflect.get(target, property, receiver);\n },\n has(target, property) {\n return property === 'i18n' ? false : Reflect.has(target, property);\n },\n ownKeys(target) {\n return Reflect.ownKeys(target).filter((property) => property !== 'i18n');\n },\n });\n }\n return _hostTrpcFacade;\n}\n\n// ============================================================\n// I18n — host translation bridge\n// ============================================================\n\nexport interface PluginI18nValue {\n pluginId?: string | undefined;\n namespace?: string | undefined;\n locale: string;\n timezone: string;\n isLoading: boolean;\n availableLocales: readonly string[];\n languages: readonly PluginLanguageOption[];\n t: (key: string, paramsOrDefault?: Record<string, string | number> | string) => string;\n /** Host-bound Core common translator. Optional for compatibility with older Hosts. */\n tCommon?: (key: string, paramsOrDefault?: Record<string, string | number> | string) => string;\n addNamespace: (namespace: string) => void;\n}\n\nexport interface PluginLanguageOption {\n locale: string;\n name: string;\n nativeName: string;\n direction: 'ltr' | 'rtl';\n isDefault: boolean;\n sortOrder: number;\n}\n\nconst fallbackPluginTranslate = (\n key: string,\n paramsOrDefault?: Record<string, string | number> | string,\n) => (typeof paramsOrDefault === 'string' ? paramsOrDefault : key);\n\nconst defaultI18n: PluginI18nValue = {\n locale: 'en-US',\n timezone: 'UTC',\n isLoading: false,\n availableLocales: [],\n languages: [],\n t: fallbackPluginTranslate,\n tCommon: fallbackPluginTranslate,\n addNamespace: () => undefined,\n};\n\nexport const PluginI18nContext = React.createContext<PluginI18nValue>(defaultI18n);\n\nfunction normalizePluginNamespace(pluginId: string): string {\n return `plugin.${pluginId}`;\n}\n\nexport function usePluginTranslation(pluginId: string, customNamespace?: string) {\n const i18n = React.useContext(PluginI18nContext);\n if (!i18n.pluginId || !i18n.namespace) {\n throw new Error('[plugin/react] Plugin i18n boundary is missing');\n }\n if (pluginId !== i18n.pluginId) {\n throw new Error(\n `[plugin/react] Plugin i18n identity mismatch: expected ${i18n.pluginId}, received ${pluginId}`,\n );\n }\n const namespace = normalizePluginNamespace(pluginId);\n if (customNamespace && customNamespace !== namespace) {\n throw new Error(\n `[plugin/react] Plugin namespace mismatch: expected ${namespace}, received ${customNamespace}`,\n );\n }\n if (i18n.namespace !== namespace) {\n throw new Error(\n `[plugin/react] Host-bound namespace mismatch: expected ${namespace}, received ${i18n.namespace}`,\n );\n }\n\n const t = React.useCallback(\n (key: string, paramsOrDefault?: Record<string, string | number> | string): string => {\n const prefix = `${namespace}.`;\n const localKey = key.startsWith(prefix) ? key.slice(prefix.length) : key;\n return i18n.t(localKey, paramsOrDefault);\n },\n [i18n],\n );\n const tCommon = i18n.tCommon ?? fallbackPluginTranslate;\n\n return React.useMemo(\n () => ({\n t,\n tCommon,\n locale: i18n.locale,\n timezone: i18n.timezone,\n isLoading: i18n.isLoading,\n availableLocales: i18n.availableLocales,\n languages: i18n.languages,\n namespace,\n }),\n [\n t,\n tCommon,\n i18n.locale,\n i18n.timezone,\n i18n.isLoading,\n i18n.availableLocales,\n i18n.languages,\n namespace,\n ],\n );\n}\n\n// ============================================================\n// Currency — host currency bridge\n// ============================================================\n\n/** Currency capabilities exposed by the Admin Host to plugin UIs. */\nexport interface PluginCurrencyValue {\n currency: CurrencyInfo;\n currencies: CurrencyInfo[];\n baseCurrency: CurrencyInfo;\n isLoading: boolean;\n isReady: boolean;\n changeCurrency: (currencyCode: string) => void;\n formatPrice: (\n cents: number,\n fromCurrency?: string | undefined,\n options?: FormatPriceOptions | undefined,\n ) => string;\n}\n\nconst defaultPluginCurrency: PluginCurrencyValue = {\n currency: DEFAULT_CURRENCY,\n currencies: [],\n baseCurrency: DEFAULT_CURRENCY,\n isLoading: false,\n isReady: false,\n changeCurrency: () => undefined,\n formatPrice: (cents, fromCurrency) => `${fromCurrency ?? DEFAULT_CURRENCY.code} ${(cents / 100).toFixed(2)}`,\n};\n\nexport const PluginCurrencyContext = React.createContext<PluginCurrencyValue>(defaultPluginCurrency);\n\nexport function usePluginCurrency(): PluginCurrencyValue {\n return React.useContext(PluginCurrencyContext);\n}\n\n// ============================================================\n// PluginSlot — runtime-injected from Admin Host\n// ============================================================\n\nexport interface PluginSlotProps {\n /** Slot name, e.g. 'shop.product.detail.actions' */\n name: string;\n /** React props passed to extensions rendered in this slot */\n props?: Record<string, unknown>;\n /** @deprecated Use props. Kept for legacy plugin slot call sites. */\n context?: Record<string, unknown>;\n /** Layout mode */\n layout?: 'inline' | 'stack' | 'tabs' | 'grid';\n /** Additional CSS class */\n className?: string;\n /** Fallback when no extensions registered */\n fallback?: React.ReactNode;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _PluginSlotImpl: React.ComponentType<PluginSlotProps> | null = null;\n\nexport interface PluginSlotRegistry {\n /** Returns whether at least one extension is registered for the slot. */\n has: (name: string) => boolean;\n /** Subscribes to extension registry changes. */\n subscribe: (onStoreChange: () => void) => () => void;\n}\n\nlet _pluginSlotRegistry: PluginSlotRegistry | null = null;\nconst emptyPluginSlotSubscribe = () => () => undefined;\n\n/**\n * Called by the Admin Host at startup to inject the PluginSlot component.\n * Plugin code should NOT call this directly.\n * @internal\n */\nexport function __setPluginSlot(component: React.ComponentType<PluginSlotProps>) {\n _PluginSlotImpl = component;\n}\n\n/**\n * Called by the Admin Host at startup to expose reactive slot availability.\n * Plugin code should NOT call this directly.\n * @internal\n */\nexport function __setPluginSlotRegistry(registry: PluginSlotRegistry | null) {\n _pluginSlotRegistry = registry;\n}\n\n/**\n * Returns whether the given slot currently has at least one registered extension.\n * The value updates when plugins are registered, reloaded, disabled, or removed.\n */\nexport function usePluginSlot(name: string): boolean {\n const getSnapshot = () => _pluginSlotRegistry?.has(name) ?? false;\n\n return React.useSyncExternalStore(\n _pluginSlotRegistry?.subscribe ?? emptyPluginSlotSubscribe,\n getSnapshot,\n getSnapshot,\n );\n}\n\n/**\n * Renders all plugin extensions registered for the given slot.\n *\n * @example\n * ```tsx\n * import { PluginSlot } from '@wordrhyme/plugin/react';\n *\n * function ProductDetailPage({ productId }) {\n * return (\n * <div>\n * <h1>Product Detail</h1>\n * <PluginSlot\n * name=\"shop.product.detail.actions\"\n * layout=\"inline\"\n * props={{ productId }}\n * />\n * </div>\n * );\n * }\n * ```\n */\nexport function PluginSlot(props: PluginSlotProps): React.ReactElement | null {\n if (!_PluginSlotImpl) {\n // Silently render nothing if host hasn't injected yet\n return null;\n }\n return React.createElement(_PluginSlotImpl, props);\n}\n\n// Ability — runtime-injected from Admin Host (CASL permission)\n// ============================================================\n\n/**\n * Minimal ability interface for plugin permission checks.\n * Matches CASL MongoAbility.can() signature.\n */\nexport interface PluginAbility {\n can(action: string, subject: string): boolean;\n}\n\n/** Default allow-all ability (when host hasn't injected) */\nconst defaultAbility: PluginAbility = { can: () => true };\n\n/**\n * React Context for ability — shared between host and plugins.\n * Host injects via AbilityBridge, plugins consume via usePluginAbility.\n */\nexport const PluginAbilityContext = React.createContext<PluginAbility>(defaultAbility);\n\n/**\n * Hook for plugin components to check permissions.\n *\n * @example\n * ```tsx\n * import { usePluginAbility } from '@wordrhyme/plugin/react';\n *\n * function MyPluginPage() {\n * const ability = usePluginAbility();\n * const canCreate = ability.can('create', 'PluginResource');\n * const canDelete = ability.can('delete', 'PluginResource');\n * }\n * ```\n */\nexport function usePluginAbility(): PluginAbility {\n return React.useContext(PluginAbilityContext);\n}\n\n// ============================================================\n// Media Picker — accesses global imperative API\n// ============================================================\n\nimport type { PluginMediaInfo } from './types';\n\n// Define the options for the global MediaPicker\nexport interface MediaPickerOptions {\n presentation?: 'dialog' | 'drawer'; // Where to open the picker\n mode?: 'single' | 'multi';\n category?: 'all' | 'image' | 'document' | 'video' | 'audio' | 'archive' | 'other';\n onSelect: (media: PluginMediaInfo[]) => void;\n}\n\n/**\n * Hook to open the global Media Picker dialog (rendered by Admin Host).\n * Returns an imperative API `openDialog(options)`.\n */\nexport function useMediaPicker() {\n return {\n openDialog: (options: MediaPickerOptions) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n if (typeof window !== 'undefined') {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n const picker = window.__WORDRHYME_MEDIA_PICKER__ || window.__OMNIDS_MEDIA_PICKER__;\n if (picker) {\n picker.open(options);\n return;\n }\n }\n console.warn('[plugin/react] Media Picker is not mounted by the Admin Host.');\n }\n };\n}\n"],"mappings":"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","names":[]}
package/dist/server.d.ts CHANGED
@@ -1,14 +1,15 @@
1
1
  export { createPluginContext, pluginProcedure, pluginRouter } from './trpc.js';
2
- import { a as PluginContext } from './types-8P7XyoyQ.js';
3
- export { H as HookContext, n as HookTransaction } from './types-8P7XyoyQ.js';
2
+ import { a as PluginContext } from './types-9v-WZ_NU.js';
3
+ export { H as HookContext, c as HookTransaction } from './types-9v-WZ_NU.js';
4
4
  import { DateRangeResolver } from './time.js';
5
5
  export { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
6
- export { E as ENTITY_EXTENSION_VALUES_SAVE_HOOK_ID, a as EXTENSION_PROJECT_SAVE_HOOK_ID, b as EntityExtensionProjectionValue, c as EntityExtensionValueSaveHandler, d as EntityExtensionValueSavePayload, e as EntityExtensionValueSaveResult, f as entityExtensions, r as registerEntityExtensionValueSaver } from './entity-extensions-B5BbZH-m.js';
6
+ export { E as ENTITY_EXTENSION_VALUES_SAVE_HOOK_ID, a as EXTENSION_PROJECT_SAVE_HOOK_ID, b as EntityExtensionProjectionValue, c as EntityExtensionValueSaveHandler, d as EntityExtensionValueSavePayload, e as EntityExtensionValueSaveResult, f as entityExtensions, r as registerEntityExtensionValueSaver } from './entity-extensions-gJuSTXYZ.js';
7
7
  import './globalization.js';
8
8
  import 'decimal.js';
9
+ import './locale.js';
9
10
  import './release-CyapqJ3z.js';
10
11
  import 'zod';
11
- import './manifest-CPSCN_Ft.js';
12
+ import './manifest-CDTCsMYV.js';
12
13
 
13
14
  interface PluginRuntimeRequestContext {
14
15
  requestId?: string | undefined;
package/dist/server.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  createPluginContext,
3
3
  pluginProcedure,
4
4
  pluginRouter
5
- } from "./chunk-ZUBFLOKU.js";
5
+ } from "./chunk-O4AYK3YP.js";
6
6
  import {
7
7
  ENTITY_EXTENSION_VALUES_SAVE_HOOK_ID,
8
8
  EXTENSION_PROJECT_SAVE_HOOK_ID,
package/dist/trpc.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import * as _trpc_server from '@trpc/server';
2
2
  export { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
3
- import { a as PluginContext } from './types-8P7XyoyQ.js';
3
+ import { a as PluginContext } from './types-9v-WZ_NU.js';
4
4
  import './globalization.js';
5
5
  import 'decimal.js';
6
+ import './locale.js';
6
7
  import './release-CyapqJ3z.js';
7
8
  import 'zod';
8
9
  import './time.js';
package/dist/trpc.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  createPluginContext,
3
3
  pluginProcedure,
4
4
  pluginRouter
5
- } from "./chunk-ZUBFLOKU.js";
5
+ } from "./chunk-O4AYK3YP.js";
6
6
  export {
7
7
  createPluginContext,
8
8
  pluginProcedure,