@asteby/metacore-runtime-react 23.11.2 → 23.12.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 23.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9376722: Add `useAddonSettings` / `useUpdateAddonSettings` — the standard primitive for reading an addon's per-organization configuration from a federated addon, backed by react-query and the host-injected api client. Merges caller-provided defaults (mirroring the manifest's `settings[].default`) under the saved org values, so a never-saved setting falls back to its default. Also exports the pure `mergeAddonSettings` helper and the stable `addonSettingsKey` query key.
8
+
3
9
  ## 23.11.2
4
10
 
5
11
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -25,6 +25,7 @@ export * from './org-runtime-provider';
25
25
  export * from './navigation-builder';
26
26
  export * from './i18n-provider';
27
27
  export * from './api-context';
28
+ export * from './use-addon-settings';
28
29
  export * from './metadata-cache';
29
30
  export { ADDON_MANIFEST_CHANGED_TYPE, wireHotSwapInvalidation, useManifestHotSwapSubscriber, type AddonManifestChangedMessage, type ManifestHotSwapClient, type WireHotSwapInvalidationOptions, } from './manifest-hotswap-subscriber';
30
31
  export { useHotSwapReload, applyHotSwapReload, withVersionParam, clearFederationContainer, shortenHash, type HotSwapReloadStrategy, type HotSwapReloadConfig, type HotSwapReloadAction, type HotSwapReloadDeps, type UseHotSwapReloadResult, } from './hotswap-reload-policy';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ export * from './org-runtime-provider';
30
30
  export * from './navigation-builder';
31
31
  export * from './i18n-provider';
32
32
  export * from './api-context';
33
+ export * from './use-addon-settings';
33
34
  export * from './metadata-cache';
34
35
  export { ADDON_MANIFEST_CHANGED_TYPE, wireHotSwapInvalidation, useManifestHotSwapSubscriber, } from './manifest-hotswap-subscriber';
35
36
  export { useHotSwapReload, applyHotSwapReload, withVersionParam, clearFederationContainer, shortenHash, } from './hotswap-reload-policy';
@@ -0,0 +1,56 @@
1
+ /** Stable react-query key for an addon's per-org settings. */
2
+ export declare function addonSettingsKey(addonKey: string): readonly ["addon-settings", string];
3
+ /**
4
+ * Merge saved org values over the caller's defaults so a never-saved setting
5
+ * falls back to its default. Pure + exported for unit testing. Only keys that
6
+ * are actually present in `stored` win — an explicit `undefined` in the stored
7
+ * payload is treated as "not saved" and yields the default (the host omits
8
+ * unsaved keys, but this keeps a sparse payload well-behaved).
9
+ */
10
+ export declare function mergeAddonSettings<T extends Record<string, unknown>>(defaults: Partial<T> | undefined, stored: Partial<T> | null | undefined): T;
11
+ export interface UseAddonSettingsOptions<T> {
12
+ /**
13
+ * Fallback values (typically the addon manifest's `settings[].default`)
14
+ * merged UNDER the saved org values. A setting the org hasn't saved
15
+ * resolves to its default here.
16
+ */
17
+ defaults?: Partial<T>;
18
+ /** Override staleTime (default 30s — org config changes rarely). */
19
+ staleTime?: number;
20
+ /** Defer fetching (e.g. until the addon key is known). */
21
+ enabled?: boolean;
22
+ }
23
+ export interface UseAddonSettingsResult<T> {
24
+ /** Saved org values merged over `defaults`. Never null. */
25
+ settings: T;
26
+ isLoading: boolean;
27
+ error: unknown;
28
+ refetch: () => void;
29
+ }
30
+ /**
31
+ * Read an addon's per-organization settings.
32
+ *
33
+ * This is the ecosystem-standard way for a federated addon to read its own
34
+ * config; prefer it over a hand-rolled fetch so every addon caches, merges
35
+ * defaults, and invalidates identically.
36
+ *
37
+ * @example
38
+ * type PosSettings = { allowNegativeStock: boolean; roundingMode: string }
39
+ * const { settings, isLoading } = useAddonSettings<PosSettings>('pos', {
40
+ * defaults: { allowNegativeStock: false, roundingMode: 'nearest' },
41
+ * })
42
+ * if (!isLoading && settings.allowNegativeStock) { ... }
43
+ */
44
+ export declare function useAddonSettings<T extends Record<string, unknown> = Record<string, unknown>>(addonKey: string, opts?: UseAddonSettingsOptions<T>): UseAddonSettingsResult<T>;
45
+ /**
46
+ * Optional write companion — PUTs a (partial) settings object and invalidates
47
+ * the read query so `useAddonSettings` re-resolves. The host's generic config
48
+ * modal does its own PUT; this exists for addons that ship a custom config
49
+ * surface. Backward-compatible: purely additive.
50
+ *
51
+ * @example
52
+ * const update = useUpdateAddonSettings('pos')
53
+ * update.mutate({ allowNegativeStock: true })
54
+ */
55
+ export declare function useUpdateAddonSettings<T extends Record<string, unknown> = Record<string, unknown>>(addonKey: string): import("@tanstack/react-query").UseMutationResult<Partial<T>, Error, Partial<T>, unknown>;
56
+ //# sourceMappingURL=use-addon-settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-addon-settings.d.ts","sourceRoot":"","sources":["../src/use-addon-settings.ts"],"names":[],"mappings":"AA6BA,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,uCAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,SAAS,EAChC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,GACtC,CAAC,CAQH;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACrB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACrC,2DAA2D;IAC3D,QAAQ,EAAE,CAAC,CAAA;IACX,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxF,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,uBAAuB,CAAC,CAAC,CAAM,GACtC,sBAAsB,CAAC,CAAC,CAAC,CA8B3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9F,QAAQ,EAAE,MAAM,6FAgBnB"}
@@ -0,0 +1,109 @@
1
+ // useAddonSettings — THE standard primitive for reading an addon's
2
+ // per-organization configuration from a federated addon (or any host
3
+ // surface) without every addon re-implementing its own fetch.
4
+ //
5
+ // The host (ops) persists settings per org on `AddonInstallation.settings`
6
+ // (jsonb) and exposes:
7
+ // GET /api/addons/:key/settings → { success, data: { <key>: <value> } }
8
+ // PUT /api/addons/:key/settings → body = object of values
9
+ // A setting the org has never saved simply isn't present in `data`; the
10
+ // caller supplies the fallback via `opts.defaults` (which mirror the
11
+ // manifest's `settings[].default`). runtime-react has no access to the
12
+ // addon manifest at runtime, so defaults are a parameter, not automatic.
13
+ //
14
+ // react-query is a PEER dependency of runtime-react: `useQuery`/`useMutation`
15
+ // resolve to the HOST's singleton QueryClient (the MF shared singleton), so
16
+ // this hook never constructs its own client and stays cache-coherent with
17
+ // the rest of the app. Do not add a QueryClientProvider here.
18
+ //
19
+ // Server-side gating (wasm/Go backends) is out of scope here: a backend that
20
+ // must gate behaviour on org config reads the same `AddonInstallation.settings`
21
+ // jsonb directly — this hook is the client-read half of that contract.
22
+ import { useMemo } from 'react';
23
+ import { useMutation, useQuery, useQueryClient, } from '@tanstack/react-query';
24
+ import { useApi } from './api-context';
25
+ /** Stable react-query key for an addon's per-org settings. */
26
+ export function addonSettingsKey(addonKey) {
27
+ return ['addon-settings', addonKey];
28
+ }
29
+ /**
30
+ * Merge saved org values over the caller's defaults so a never-saved setting
31
+ * falls back to its default. Pure + exported for unit testing. Only keys that
32
+ * are actually present in `stored` win — an explicit `undefined` in the stored
33
+ * payload is treated as "not saved" and yields the default (the host omits
34
+ * unsaved keys, but this keeps a sparse payload well-behaved).
35
+ */
36
+ export function mergeAddonSettings(defaults, stored) {
37
+ const out = { ...(defaults ?? {}) };
38
+ if (stored) {
39
+ for (const [k, v] of Object.entries(stored)) {
40
+ if (v !== undefined)
41
+ out[k] = v;
42
+ }
43
+ }
44
+ return out;
45
+ }
46
+ /**
47
+ * Read an addon's per-organization settings.
48
+ *
49
+ * This is the ecosystem-standard way for a federated addon to read its own
50
+ * config; prefer it over a hand-rolled fetch so every addon caches, merges
51
+ * defaults, and invalidates identically.
52
+ *
53
+ * @example
54
+ * type PosSettings = { allowNegativeStock: boolean; roundingMode: string }
55
+ * const { settings, isLoading } = useAddonSettings<PosSettings>('pos', {
56
+ * defaults: { allowNegativeStock: false, roundingMode: 'nearest' },
57
+ * })
58
+ * if (!isLoading && settings.allowNegativeStock) { ... }
59
+ */
60
+ export function useAddonSettings(addonKey, opts = {}) {
61
+ const api = useApi();
62
+ const { defaults, staleTime, enabled } = opts;
63
+ const query = useQuery({
64
+ queryKey: addonSettingsKey(addonKey),
65
+ queryFn: async () => {
66
+ const res = await api.get(`/api/addons/${addonKey}/settings`);
67
+ const body = res.data;
68
+ // Host envelope: { success, data: { <key>: <value> } }.
69
+ const values = body?.success ? body.data : body;
70
+ return (values ?? {});
71
+ },
72
+ staleTime: staleTime ?? 30_000,
73
+ enabled: (enabled ?? true) && !!addonKey,
74
+ });
75
+ const settings = useMemo(() => mergeAddonSettings(defaults, query.data), [defaults, query.data]);
76
+ return {
77
+ settings,
78
+ isLoading: query.isLoading,
79
+ error: query.error,
80
+ refetch: () => {
81
+ void query.refetch();
82
+ },
83
+ };
84
+ }
85
+ /**
86
+ * Optional write companion — PUTs a (partial) settings object and invalidates
87
+ * the read query so `useAddonSettings` re-resolves. The host's generic config
88
+ * modal does its own PUT; this exists for addons that ship a custom config
89
+ * surface. Backward-compatible: purely additive.
90
+ *
91
+ * @example
92
+ * const update = useUpdateAddonSettings('pos')
93
+ * update.mutate({ allowNegativeStock: true })
94
+ */
95
+ export function useUpdateAddonSettings(addonKey) {
96
+ const api = useApi();
97
+ const qc = useQueryClient();
98
+ return useMutation({
99
+ mutationFn: async (values) => {
100
+ const res = await api.put(`/api/addons/${addonKey}/settings`, values);
101
+ const body = res.data;
102
+ const saved = body?.success ? body.data : body;
103
+ return (saved ?? values);
104
+ },
105
+ onSuccess: () => {
106
+ void qc.invalidateQueries({ queryKey: addonSettingsKey(addonKey) });
107
+ },
108
+ });
109
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-runtime-react",
3
- "version": "23.11.2",
3
+ "version": "23.12.0",
4
4
  "description": "React runtime for metacore hosts — renders addon contributions dynamically",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,74 @@
1
+ // Locks the default-merge semantics of the useAddonSettings primitive: saved
2
+ // org values win over caller defaults, never-saved keys fall back to their
3
+ // default, and a sparse/undefined stored payload stays well-behaved. The hook
4
+ // itself is a thin react-query wrapper over `useApi`; the load-bearing logic
5
+ // is this pure merge, so that's what we test directly.
6
+ import { describe, it, expect } from 'vitest'
7
+ import { mergeAddonSettings, addonSettingsKey } from '../use-addon-settings'
8
+
9
+ interface PosSettings extends Record<string, unknown> {
10
+ allowNegativeStock: boolean
11
+ roundingMode: string
12
+ taxRate: number
13
+ }
14
+
15
+ describe('mergeAddonSettings', () => {
16
+ const defaults: Partial<PosSettings> = {
17
+ allowNegativeStock: false,
18
+ roundingMode: 'nearest',
19
+ taxRate: 0,
20
+ }
21
+
22
+ it('falls back to defaults when nothing is stored', () => {
23
+ expect(mergeAddonSettings<PosSettings>(defaults, null)).toEqual({
24
+ allowNegativeStock: false,
25
+ roundingMode: 'nearest',
26
+ taxRate: 0,
27
+ })
28
+ expect(mergeAddonSettings<PosSettings>(defaults, undefined)).toEqual(defaults)
29
+ expect(mergeAddonSettings<PosSettings>(defaults, {})).toEqual(defaults)
30
+ })
31
+
32
+ it('lets saved org values override defaults', () => {
33
+ expect(
34
+ mergeAddonSettings<PosSettings>(defaults, { allowNegativeStock: true, taxRate: 16 }),
35
+ ).toEqual({
36
+ allowNegativeStock: true,
37
+ roundingMode: 'nearest',
38
+ taxRate: 16,
39
+ })
40
+ })
41
+
42
+ it('keeps falsy saved values (0, false, "") instead of treating them as unset', () => {
43
+ expect(
44
+ mergeAddonSettings<PosSettings>(
45
+ { allowNegativeStock: true, roundingMode: 'up', taxRate: 5 },
46
+ { allowNegativeStock: false, roundingMode: '', taxRate: 0 },
47
+ ),
48
+ ).toEqual({ allowNegativeStock: false, roundingMode: '', taxRate: 0 })
49
+ })
50
+
51
+ it('treats an explicit undefined in the stored payload as unset', () => {
52
+ expect(
53
+ mergeAddonSettings<PosSettings>(defaults, { roundingMode: undefined }),
54
+ ).toEqual(defaults)
55
+ })
56
+
57
+ it('returns an object even with no defaults', () => {
58
+ expect(mergeAddonSettings(undefined, { a: 1 })).toEqual({ a: 1 })
59
+ expect(mergeAddonSettings(undefined, null)).toEqual({})
60
+ })
61
+
62
+ it('does not mutate the provided defaults object', () => {
63
+ const d = { ...defaults }
64
+ mergeAddonSettings<PosSettings>(d, { taxRate: 99 })
65
+ expect(d).toEqual(defaults)
66
+ })
67
+ })
68
+
69
+ describe('addonSettingsKey', () => {
70
+ it('is stable and namespaced per addon', () => {
71
+ expect(addonSettingsKey('pos')).toEqual(['addon-settings', 'pos'])
72
+ expect(addonSettingsKey('inventory')).toEqual(['addon-settings', 'inventory'])
73
+ })
74
+ })
package/src/index.ts CHANGED
@@ -165,6 +165,7 @@ export * from './org-runtime-provider'
165
165
  export * from './navigation-builder'
166
166
  export * from './i18n-provider'
167
167
  export * from './api-context'
168
+ export * from './use-addon-settings'
168
169
  export * from './metadata-cache'
169
170
  export {
170
171
  ADDON_MANIFEST_CHANGED_TYPE,
@@ -0,0 +1,152 @@
1
+ // useAddonSettings — THE standard primitive for reading an addon's
2
+ // per-organization configuration from a federated addon (or any host
3
+ // surface) without every addon re-implementing its own fetch.
4
+ //
5
+ // The host (ops) persists settings per org on `AddonInstallation.settings`
6
+ // (jsonb) and exposes:
7
+ // GET /api/addons/:key/settings → { success, data: { <key>: <value> } }
8
+ // PUT /api/addons/:key/settings → body = object of values
9
+ // A setting the org has never saved simply isn't present in `data`; the
10
+ // caller supplies the fallback via `opts.defaults` (which mirror the
11
+ // manifest's `settings[].default`). runtime-react has no access to the
12
+ // addon manifest at runtime, so defaults are a parameter, not automatic.
13
+ //
14
+ // react-query is a PEER dependency of runtime-react: `useQuery`/`useMutation`
15
+ // resolve to the HOST's singleton QueryClient (the MF shared singleton), so
16
+ // this hook never constructs its own client and stays cache-coherent with
17
+ // the rest of the app. Do not add a QueryClientProvider here.
18
+ //
19
+ // Server-side gating (wasm/Go backends) is out of scope here: a backend that
20
+ // must gate behaviour on org config reads the same `AddonInstallation.settings`
21
+ // jsonb directly — this hook is the client-read half of that contract.
22
+ import { useMemo } from 'react'
23
+ import {
24
+ useMutation,
25
+ useQuery,
26
+ useQueryClient,
27
+ } from '@tanstack/react-query'
28
+ import { useApi } from './api-context'
29
+
30
+ /** Stable react-query key for an addon's per-org settings. */
31
+ export function addonSettingsKey(addonKey: string) {
32
+ return ['addon-settings', addonKey] as const
33
+ }
34
+
35
+ /**
36
+ * Merge saved org values over the caller's defaults so a never-saved setting
37
+ * falls back to its default. Pure + exported for unit testing. Only keys that
38
+ * are actually present in `stored` win — an explicit `undefined` in the stored
39
+ * payload is treated as "not saved" and yields the default (the host omits
40
+ * unsaved keys, but this keeps a sparse payload well-behaved).
41
+ */
42
+ export function mergeAddonSettings<T extends Record<string, unknown>>(
43
+ defaults: Partial<T> | undefined,
44
+ stored: Partial<T> | null | undefined,
45
+ ): T {
46
+ const out: Record<string, unknown> = { ...(defaults ?? {}) }
47
+ if (stored) {
48
+ for (const [k, v] of Object.entries(stored)) {
49
+ if (v !== undefined) out[k] = v
50
+ }
51
+ }
52
+ return out as T
53
+ }
54
+
55
+ export interface UseAddonSettingsOptions<T> {
56
+ /**
57
+ * Fallback values (typically the addon manifest's `settings[].default`)
58
+ * merged UNDER the saved org values. A setting the org hasn't saved
59
+ * resolves to its default here.
60
+ */
61
+ defaults?: Partial<T>
62
+ /** Override staleTime (default 30s — org config changes rarely). */
63
+ staleTime?: number
64
+ /** Defer fetching (e.g. until the addon key is known). */
65
+ enabled?: boolean
66
+ }
67
+
68
+ export interface UseAddonSettingsResult<T> {
69
+ /** Saved org values merged over `defaults`. Never null. */
70
+ settings: T
71
+ isLoading: boolean
72
+ error: unknown
73
+ refetch: () => void
74
+ }
75
+
76
+ /**
77
+ * Read an addon's per-organization settings.
78
+ *
79
+ * This is the ecosystem-standard way for a federated addon to read its own
80
+ * config; prefer it over a hand-rolled fetch so every addon caches, merges
81
+ * defaults, and invalidates identically.
82
+ *
83
+ * @example
84
+ * type PosSettings = { allowNegativeStock: boolean; roundingMode: string }
85
+ * const { settings, isLoading } = useAddonSettings<PosSettings>('pos', {
86
+ * defaults: { allowNegativeStock: false, roundingMode: 'nearest' },
87
+ * })
88
+ * if (!isLoading && settings.allowNegativeStock) { ... }
89
+ */
90
+ export function useAddonSettings<T extends Record<string, unknown> = Record<string, unknown>>(
91
+ addonKey: string,
92
+ opts: UseAddonSettingsOptions<T> = {},
93
+ ): UseAddonSettingsResult<T> {
94
+ const api = useApi()
95
+ const { defaults, staleTime, enabled } = opts
96
+
97
+ const query = useQuery<Partial<T>>({
98
+ queryKey: addonSettingsKey(addonKey),
99
+ queryFn: async () => {
100
+ const res = await api.get(`/api/addons/${addonKey}/settings`)
101
+ const body = (res as { data: any }).data
102
+ // Host envelope: { success, data: { <key>: <value> } }.
103
+ const values = body?.success ? body.data : body
104
+ return (values ?? {}) as Partial<T>
105
+ },
106
+ staleTime: staleTime ?? 30_000,
107
+ enabled: (enabled ?? true) && !!addonKey,
108
+ })
109
+
110
+ const settings = useMemo(
111
+ () => mergeAddonSettings<T>(defaults, query.data),
112
+ [defaults, query.data],
113
+ )
114
+
115
+ return {
116
+ settings,
117
+ isLoading: query.isLoading,
118
+ error: query.error,
119
+ refetch: () => {
120
+ void query.refetch()
121
+ },
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Optional write companion — PUTs a (partial) settings object and invalidates
127
+ * the read query so `useAddonSettings` re-resolves. The host's generic config
128
+ * modal does its own PUT; this exists for addons that ship a custom config
129
+ * surface. Backward-compatible: purely additive.
130
+ *
131
+ * @example
132
+ * const update = useUpdateAddonSettings('pos')
133
+ * update.mutate({ allowNegativeStock: true })
134
+ */
135
+ export function useUpdateAddonSettings<T extends Record<string, unknown> = Record<string, unknown>>(
136
+ addonKey: string,
137
+ ) {
138
+ const api = useApi()
139
+ const qc = useQueryClient()
140
+
141
+ return useMutation<Partial<T>, Error, Partial<T>>({
142
+ mutationFn: async (values) => {
143
+ const res = await api.put(`/api/addons/${addonKey}/settings`, values)
144
+ const body = (res as { data: any }).data
145
+ const saved = body?.success ? body.data : body
146
+ return (saved ?? values) as Partial<T>
147
+ },
148
+ onSuccess: () => {
149
+ void qc.invalidateQueries({ queryKey: addonSettingsKey(addonKey) })
150
+ },
151
+ })
152
+ }