@happyvertical/smrt-fields 0.40.61 → 0.40.63

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 (78) hide show
  1. package/AGENTS.md +18 -0
  2. package/README.md +125 -112
  3. package/dist/chunks/FieldPolicyCollection--RxukfCX.js +1218 -0
  4. package/dist/chunks/FieldPolicyCollection--RxukfCX.js.map +1 -0
  5. package/dist/collections/FieldPolicySuggestionCollection.d.ts +160 -0
  6. package/dist/collections/FieldPolicySuggestionCollection.d.ts.map +1 -0
  7. package/dist/collections/FieldUsageCounterCollection.d.ts +143 -0
  8. package/dist/collections/FieldUsageCounterCollection.d.ts.map +1 -0
  9. package/dist/deterministic-id.d.ts +18 -0
  10. package/dist/deterministic-id.d.ts.map +1 -0
  11. package/dist/field-definitions.d.ts +8 -0
  12. package/dist/field-definitions.d.ts.map +1 -1
  13. package/dist/index.d.ts +8 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1565 -1077
  16. package/dist/index.js.map +1 -1
  17. package/dist/manifest.json +1442 -188
  18. package/dist/models/FieldPolicySuggestion.d.ts +132 -0
  19. package/dist/models/FieldPolicySuggestion.d.ts.map +1 -0
  20. package/dist/models/FieldUsageCounter.d.ts +178 -0
  21. package/dist/models/FieldUsageCounter.d.ts.map +1 -0
  22. package/dist/models/FieldUsageReportReceipt.d.ts +25 -0
  23. package/dist/models/FieldUsageReportReceipt.d.ts.map +1 -0
  24. package/dist/smrt-knowledge.json +404 -7
  25. package/dist/svelte/__tests__/FieldPolicyControlPanel.test.js +54 -0
  26. package/dist/svelte/__tests__/FormHelp.test.js +8 -0
  27. package/dist/svelte/__tests__/ObjectForm.test.js +131 -0
  28. package/dist/svelte/__tests__/UsageLearning.test.js +140 -0
  29. package/dist/svelte/__tests__/fixtures/ObjectFormActionsFixture.svelte +21 -4
  30. package/dist/svelte/__tests__/fixtures/ObjectFormActionsFixture.svelte.d.ts +5 -1
  31. package/dist/svelte/__tests__/fixtures/ObjectFormActionsFixture.svelte.d.ts.map +1 -1
  32. package/dist/svelte/__tests__/fixtures/SuggestionGearFixture.svelte +23 -0
  33. package/dist/svelte/__tests__/fixtures/SuggestionGearFixture.svelte.d.ts +10 -0
  34. package/dist/svelte/__tests__/fixtures/SuggestionGearFixture.svelte.d.ts.map +1 -0
  35. package/dist/svelte/__tests__/playground.test.js +66 -0
  36. package/dist/svelte/components/FieldPolicyControlPanel.svelte +28 -1
  37. package/dist/svelte/components/FieldPolicyControlPanel.svelte.d.ts +3 -0
  38. package/dist/svelte/components/FieldPolicyControlPanel.svelte.d.ts.map +1 -1
  39. package/dist/svelte/components/FieldPolicyGearButton.svelte +8 -1
  40. package/dist/svelte/components/FieldPolicyGearButton.svelte.d.ts.map +1 -1
  41. package/dist/svelte/components/FieldPolicyGearProvider.svelte +34 -0
  42. package/dist/svelte/components/FieldPolicyGearProvider.svelte.d.ts +3 -0
  43. package/dist/svelte/components/FieldPolicyGearProvider.svelte.d.ts.map +1 -1
  44. package/dist/svelte/components/FieldPolicySuggestionQueue.svelte +135 -0
  45. package/dist/svelte/components/FieldPolicySuggestionQueue.svelte.d.ts +11 -0
  46. package/dist/svelte/components/FieldPolicySuggestionQueue.svelte.d.ts.map +1 -0
  47. package/dist/svelte/components/FormHelp.svelte +16 -1
  48. package/dist/svelte/components/FormHelp.svelte.d.ts.map +1 -1
  49. package/dist/svelte/components/ObjectForm.svelte +91 -2
  50. package/dist/svelte/components/ObjectForm.svelte.d.ts +11 -1
  51. package/dist/svelte/components/ObjectForm.svelte.d.ts.map +1 -1
  52. package/dist/svelte/context.svelte.d.ts +15 -0
  53. package/dist/svelte/context.svelte.d.ts.map +1 -1
  54. package/dist/svelte/context.svelte.js +15 -0
  55. package/dist/svelte/gear-context.svelte.d.ts +2 -0
  56. package/dist/svelte/gear-context.svelte.d.ts.map +1 -1
  57. package/dist/svelte/index.d.ts +6 -1
  58. package/dist/svelte/index.d.ts.map +1 -1
  59. package/dist/svelte/index.js +4 -1
  60. package/dist/svelte/playground/FieldPolicyFormPreview.svelte +18 -12
  61. package/dist/svelte/playground/FieldPolicyFormPreview.svelte.d.ts.map +1 -1
  62. package/dist/svelte/suggestions.d.ts +38 -0
  63. package/dist/svelte/suggestions.d.ts.map +1 -0
  64. package/dist/svelte/suggestions.js +68 -0
  65. package/dist/svelte/usage-capture.d.ts +63 -0
  66. package/dist/svelte/usage-capture.d.ts.map +1 -0
  67. package/dist/svelte/usage-capture.js +61 -0
  68. package/dist/types.d.ts +40 -0
  69. package/dist/types.d.ts.map +1 -1
  70. package/dist/types.js +7 -1
  71. package/dist/types.js.map +1 -1
  72. package/dist/usage-learning.d.ts +201 -0
  73. package/dist/usage-learning.d.ts.map +1 -0
  74. package/dist/usage-schedules.d.ts +110 -0
  75. package/dist/usage-schedules.d.ts.map +1 -0
  76. package/dist/users-module.d.ts +30 -0
  77. package/dist/users-module.d.ts.map +1 -0
  78. package/package.json +9 -9
@@ -1,6 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import { type FieldPolicyEditorAdapter, type FieldPolicyOrganizationScope } from '../field-policy-editor.js';
3
3
  import type { FieldInputRegistry } from '../input-registry.js';
4
+ import { type FieldPolicySuggestionAdapter } from '../suggestions.js';
4
5
  import type { ObjectFormFieldDefinition } from '../types.js';
5
6
  interface Props {
6
7
  objectRef: string;
@@ -9,6 +10,8 @@ interface Props {
9
10
  inputRegistry?: FieldInputRegistry;
10
11
  /** Hosts in an app-wide context pass app; tenant hosts retain the default. */
11
12
  organizationScope?: FieldPolicyOrganizationScope;
13
+ /** Optional reviewed-suggestion transport for the gear badge. */
14
+ suggestionAdapter?: FieldPolicySuggestionAdapter;
12
15
  children?: Snippet;
13
16
  }
14
17
  declare const FieldPolicyGearProvider: import("svelte").Component<Props, {}, "">;
@@ -1 +1 @@
1
- {"version":3,"file":"FieldPolicyGearProvider.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/FieldPolicyGearProvider.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EAElC,MAAM,2BAA2B,CAAC;AAKnC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAI7D,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAC5D,OAAO,EAAE,wBAAwB,CAAC;IAClC,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAuHD,QAAA,MAAM,uBAAuB,2CAAwC,CAAC;AACtE,KAAK,uBAAuB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAC1E,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"FieldPolicyGearProvider.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/FieldPolicyGearProvider.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EAElC,MAAM,2BAA2B,CAAC;AAKnC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EACL,KAAK,4BAA4B,EAElC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAI7D,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAC5D,OAAO,EAAE,wBAAwB,CAAC;IAClC,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;IACjD,iEAAiE;IACjE,iBAAiB,CAAC,EAAE,4BAA4B,CAAC;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAoJD,QAAA,MAAM,uBAAuB,2CAAwC,CAAC;AACtE,KAAK,uBAAuB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAC1E,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,135 @@
1
+ <script lang="ts">
2
+ /** Accessible, host-transport-neutral review queue for pending suggestions. */
3
+ import { Button } from '@happyvertical/smrt-ui/ui';
4
+ import {
5
+ type FieldPolicySuggestion,
6
+ type FieldPolicySuggestionAdapter,
7
+ fieldPolicySuggestionEvidence,
8
+ parsePendingFieldPolicySuggestions,
9
+ } from '../suggestions.js';
10
+
11
+ export interface FieldPolicySuggestionQueueProps {
12
+ adapter: FieldPolicySuggestionAdapter;
13
+ objectRefs?: readonly string[];
14
+ heading?: string;
15
+ onchanged?: () => void;
16
+ }
17
+
18
+ let {
19
+ adapter,
20
+ objectRefs,
21
+ heading = 'Pending field suggestions',
22
+ onchanged,
23
+ }: FieldPolicySuggestionQueueProps = $props();
24
+
25
+ let suggestions = $state<FieldPolicySuggestion[]>([]);
26
+ let total = $state(0);
27
+ let loading = $state(false);
28
+ let busyId = $state<string | null>(null);
29
+ let error = $state<string | null>(null);
30
+ let generation = 0;
31
+
32
+ async function load(): Promise<void> {
33
+ const token = ++generation;
34
+ loading = true;
35
+ error = null;
36
+ try {
37
+ const result = parsePendingFieldPolicySuggestions(
38
+ await adapter.pendingSuggestions(
39
+ objectRefs?.length ? { objectRefs } : undefined,
40
+ ),
41
+ );
42
+ if (token !== generation) return;
43
+ suggestions = result.suggestions;
44
+ total = result.total;
45
+ } catch (cause) {
46
+ if (token !== generation) return;
47
+ suggestions = [];
48
+ total = 0;
49
+ error =
50
+ cause instanceof Error
51
+ ? cause.message
52
+ : 'Unable to load pending field suggestions.';
53
+ } finally {
54
+ if (token === generation) loading = false;
55
+ }
56
+ }
57
+
58
+ async function decide(
59
+ suggestion: FieldPolicySuggestion,
60
+ decision: 'approve' | 'dismiss',
61
+ ): Promise<void> {
62
+ if (busyId) return;
63
+ busyId = suggestion.id;
64
+ error = null;
65
+ try {
66
+ if (decision === 'approve') {
67
+ await adapter.acceptSuggestion({ id: suggestion.id });
68
+ } else {
69
+ await adapter.dismissSuggestion({ id: suggestion.id });
70
+ }
71
+ await load();
72
+ onchanged?.();
73
+ } catch (cause) {
74
+ error =
75
+ cause instanceof Error
76
+ ? cause.message
77
+ : 'Unable to update this field suggestion.';
78
+ } finally {
79
+ busyId = null;
80
+ }
81
+ }
82
+
83
+ $effect(() => {
84
+ adapter;
85
+ objectRefs;
86
+ void load();
87
+ });
88
+
89
+ function description(suggestion: FieldPolicySuggestion): string {
90
+ return suggestion.kind === 'promote'
91
+ ? `Promote ${suggestion.fieldName} to the basic form.`
92
+ : `Set an organization default for ${suggestion.fieldName}.`;
93
+ }
94
+ </script>
95
+
96
+ <section class="field-policy-suggestion-queue" aria-label={heading}>
97
+ <header>
98
+ <h2>{heading}</h2>
99
+ {#if !loading}<span class="field-policy-suggestion-queue__count">{total}</span>{/if}
100
+ </header>
101
+ {#if loading}
102
+ <p role="status" aria-live="polite">Loading pending suggestions…</p>
103
+ {:else if error}
104
+ <p role="alert">{error}</p>
105
+ {:else if suggestions.length === 0}
106
+ <p>No pending field suggestions.</p>
107
+ {:else}
108
+ <ul>
109
+ {#each suggestions as suggestion (suggestion.id)}
110
+ <li>
111
+ <article>
112
+ <h3>{suggestion.objectRef} · {suggestion.fieldName}</h3>
113
+ <p>{description(suggestion)}</p>
114
+ <p>{fieldPolicySuggestionEvidence(suggestion)}</p>
115
+ <div class="field-policy-suggestion-queue__actions">
116
+ <Button type="button" disabled={busyId !== null} onclick={() => decide(suggestion, 'approve')}>Approve</Button>
117
+ <Button type="button" variant="ghost" disabled={busyId !== null} onclick={() => decide(suggestion, 'dismiss')}>Dismiss</Button>
118
+ </div>
119
+ </article>
120
+ </li>
121
+ {/each}
122
+ </ul>
123
+ {/if}
124
+ </section>
125
+
126
+ <style>
127
+ .field-policy-suggestion-queue { display: grid; gap: var(--smrt-spacing-3, 0.75rem); }
128
+ .field-policy-suggestion-queue header { align-items: center; display: flex; gap: var(--smrt-spacing-2, 0.5rem); }
129
+ .field-policy-suggestion-queue h2, .field-policy-suggestion-queue h3 { margin: 0; }
130
+ .field-policy-suggestion-queue__count { border-radius: 999px; background: var(--smrt-color-secondary-container, #e8def8); min-inline-size: 1.5rem; padding: 0.125rem 0.4rem; text-align: center; }
131
+ .field-policy-suggestion-queue ul { display: grid; gap: var(--smrt-spacing-3, 0.75rem); list-style: none; margin: 0; padding: 0; }
132
+ .field-policy-suggestion-queue article { border: 1px solid var(--smrt-color-outline-variant, currentColor); border-radius: var(--smrt-radius-small, 0.25rem); display: grid; gap: var(--smrt-spacing-2, 0.5rem); padding: var(--smrt-spacing-3, 0.75rem); }
133
+ .field-policy-suggestion-queue article p { margin: 0; }
134
+ .field-policy-suggestion-queue__actions { display: flex; flex-wrap: wrap; gap: var(--smrt-spacing-2, 0.5rem); }
135
+ </style>
@@ -0,0 +1,11 @@
1
+ import { type FieldPolicySuggestionAdapter } from '../suggestions.js';
2
+ export interface FieldPolicySuggestionQueueProps {
3
+ adapter: FieldPolicySuggestionAdapter;
4
+ objectRefs?: readonly string[];
5
+ heading?: string;
6
+ onchanged?: () => void;
7
+ }
8
+ declare const FieldPolicySuggestionQueue: import("svelte").Component<FieldPolicySuggestionQueueProps, {}, "">;
9
+ type FieldPolicySuggestionQueue = ReturnType<typeof FieldPolicySuggestionQueue>;
10
+ export default FieldPolicySuggestionQueue;
11
+ //# sourceMappingURL=FieldPolicySuggestionQueue.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FieldPolicySuggestionQueue.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/FieldPolicySuggestionQueue.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,4BAA4B,EAGlC,MAAM,mBAAmB,CAAC;AAG3B,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,4BAA4B,CAAC;IACtC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAuHD,QAAA,MAAM,0BAA0B,qEAAwC,CAAC;AACzE,KAAK,0BAA0B,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAChF,eAAe,0BAA0B,CAAC"}
@@ -9,7 +9,22 @@
9
9
  * plus the object description if provided. The data comes entirely from the
10
10
  * resolved policy — no separate fetch needed.
11
11
  *
12
- * Must be used inside a FieldPolicyProvider.
12
+ * Must be used inside a FieldPolicyProvider — deliberately, via the throwing
13
+ * accessor. The panel's payload IS the resolved glossary, so with no provider
14
+ * there is nothing to assemble and a `?` affordance that opens onto "No field
15
+ * help available." would hide the mistake instead of reporting it. This matches
16
+ * the other provider-only compositions (`ModeSwitch`, `AdvancedFields`);
17
+ * `PolicyField` degrades instead only because it has caller-owned children to
18
+ * render verbatim.
19
+ *
20
+ * To put form help in a page header, extend the SAME provider over the header —
21
+ * it renders no markup of its own. Do not add a second one: each provider owns
22
+ * its own mode store and shadows the outer for its subtree, so a `FormHelp`
23
+ * above a nested provider stops tracking the `ModeSwitch` inside it (#2272).
24
+ *
25
+ * Inside `ObjectForm`, which builds its own provider, use its `actions` snippet
26
+ * — it renders within that provider, so the glossary resolves. There is no
27
+ * header seam, so it lands below the fields; tracked in #2289.
13
28
  */
14
29
  import { getFieldPolicyContext } from '../context.svelte.js';
15
30
 
@@ -1 +1 @@
1
- {"version":3,"file":"FormHelp.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/FormHelp.svelte.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,KAAK;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAuED,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"FormHelp.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/FormHelp.svelte.ts"],"names":[],"mappings":"AAiCA,MAAM,WAAW,KAAK;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAuED,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
@@ -21,6 +21,11 @@ import {
21
21
  type ObjectFormFieldDefinition,
22
22
  type ObjectFormFieldSnippetProps,
23
23
  } from '../types.js';
24
+ import {
25
+ collectFieldUsageEntries,
26
+ type FieldUsageReporter,
27
+ reportFieldUsage,
28
+ } from '../usage-capture.js';
24
29
  import AdvancedFields from './AdvancedFields.svelte';
25
30
  import FieldInput from './FieldInput.svelte';
26
31
  import FieldPolicyGearButton from './FieldPolicyGearButton.svelte';
@@ -57,10 +62,23 @@ export interface ObjectFormProps {
57
62
  renderers?: Readonly<Record<string, Snippet<[ObjectFormFieldSnippetProps]>>>;
58
63
  /** Optional controls rendered after the policy-ordered fields inside the form. */
59
64
  actions?: Snippet;
65
+ /**
66
+ * Optional telemetry transport. It runs only when `onsubmit` explicitly
67
+ * resolves `true` after persistence; identity and field sensitivity remain
68
+ * server-derived.
69
+ */
70
+ usageReporter?: FieldUsageReporter;
60
71
  class?: string;
61
- onsubmit?: (event: SubmitEvent) => void;
72
+ /** Return true only after the host has persisted this record successfully. */
73
+ onsubmit?: ObjectFormSubmitHandler;
62
74
  }
63
75
 
76
+ // biome-ignore lint/suspicious/noConfusingVoidType: void handlers remain a supported legacy integration and never acknowledge persistence.
77
+ export type ObjectFormSubmitAcknowledgement = boolean | void;
78
+ export type ObjectFormSubmitHandler = (
79
+ event: SubmitEvent,
80
+ ) => ObjectFormSubmitAcknowledgement | Promise<ObjectFormSubmitAcknowledgement>;
81
+
64
82
  let {
65
83
  objectRef,
66
84
  fields = undefined,
@@ -74,6 +92,7 @@ let {
74
92
  inputRegistry,
75
93
  renderers = {},
76
94
  actions,
95
+ usageReporter,
77
96
  class: className = '',
78
97
  onsubmit,
79
98
  }: ObjectFormProps = $props();
@@ -201,6 +220,76 @@ function fieldId(name: string): string {
201
220
  return `${formInstanceId}-${name}`;
202
221
  }
203
222
 
223
+ function captureUsage(values: Readonly<Record<string, unknown>>): void {
224
+ if (!resolvedPolicy) return;
225
+ reportFieldUsage(
226
+ usageReporter,
227
+ collectFieldUsageEntries({
228
+ objectRef,
229
+ values,
230
+ // Hidden fields are not submitted user inputs. Basic and advanced fields
231
+ // are included even when a value matches the default so the server's
232
+ // dominance calculation has a complete denominator.
233
+ fields: Object.fromEntries(
234
+ formFields
235
+ .filter(
236
+ (field) =>
237
+ resolvedPolicy.fields[field.name].visibility !== 'hidden',
238
+ )
239
+ .map((field) => [field.name, field.definition.type]),
240
+ ),
241
+ defaults: Object.fromEntries(
242
+ formFields
243
+ .filter(
244
+ (field) =>
245
+ resolvedPolicy.fields[field.name].visibility !== 'hidden',
246
+ )
247
+ .map((field) => {
248
+ const resolved = resolvedPolicy.fields[field.name];
249
+ return [
250
+ field.name,
251
+ {
252
+ hasDefault: resolved.hasDefault,
253
+ defaultValue: resolved.defaultValue,
254
+ },
255
+ ];
256
+ }),
257
+ ),
258
+ }),
259
+ );
260
+ }
261
+
262
+ async function handleSubmit(event: SubmitEvent): Promise<void> {
263
+ if (invalidFields.size > 0) {
264
+ event.preventDefault();
265
+ return;
266
+ }
267
+ if (!onsubmit) return;
268
+ // A successful create commonly replaces the bound record before its
269
+ // persistence promise resolves. Snapshot before awaiting so usage describes
270
+ // the fields that were submitted, not the newly cleared next-record state.
271
+ const submittedValues = snapshotUsageValues(value);
272
+ try {
273
+ // Form prevents native navigation itself, so persistence acknowledgement
274
+ // must be explicit rather than inferred from event.defaultPrevented.
275
+ if ((await onsubmit(event)) === true) captureUsage(submittedValues);
276
+ } catch {
277
+ // The host owns persistence errors; rejected submissions never emit usage.
278
+ }
279
+ }
280
+
281
+ function snapshotUsageValues(
282
+ record: Readonly<Record<string, unknown>>,
283
+ ): Record<string, unknown> {
284
+ try {
285
+ return structuredClone(record);
286
+ } catch {
287
+ // Generated form values are wire-safe, but retain a shallow fallback for
288
+ // host extensions that add an uncloneable value outside telemetry fields.
289
+ return { ...record };
290
+ }
291
+ }
292
+
204
293
  // Apply policy defaults to a create record once, before a user can interact
205
294
  // with any control. This preserves JSON and boolean defaults (which cannot be
206
295
  // faithfully inferred from generic DOM string assignment) and means callers
@@ -330,7 +419,7 @@ function inputFor(field: ObjectFormField): FieldInputComponent {
330
419
  <div class="object-form__gear"><FieldPolicyGearButton /></div>
331
420
  {/if}
332
421
  {/if}
333
- <Form class="object-form {className}" onsubmit={(event) => { if (invalidFields.size > 0) { event.preventDefault(); return; } onsubmit?.(event); }}>
422
+ <Form class="object-form {className}" onsubmit={handleSubmit}>
334
423
  {@render renderGroups(basicGroups)}
335
424
  {#if advancedGroups.length > 0}
336
425
  <AdvancedFields open>
@@ -2,6 +2,9 @@ import type { Component, Snippet } from 'svelte';
2
2
  import type { ResolvedObjectFieldPolicy } from '../../types.js';
3
3
  import type { FieldInputRegistry } from '../input-registry.js';
4
4
  import { type ObjectFormFieldDefinition, type ObjectFormFieldSnippetProps } from '../types.js';
5
+ import { type FieldUsageReporter } from '../usage-capture.js';
6
+ export type ObjectFormSubmitAcknowledgement = boolean | void;
7
+ export type ObjectFormSubmitHandler = (event: SubmitEvent) => ObjectFormSubmitAcknowledgement | Promise<ObjectFormSubmitAcknowledgement>;
5
8
  export interface ObjectFormProps {
6
9
  objectRef: string;
7
10
  /**
@@ -31,8 +34,15 @@ export interface ObjectFormProps {
31
34
  renderers?: Readonly<Record<string, Snippet<[ObjectFormFieldSnippetProps]>>>;
32
35
  /** Optional controls rendered after the policy-ordered fields inside the form. */
33
36
  actions?: Snippet;
37
+ /**
38
+ * Optional telemetry transport. It runs only when `onsubmit` explicitly
39
+ * resolves `true` after persistence; identity and field sensitivity remain
40
+ * server-derived.
41
+ */
42
+ usageReporter?: FieldUsageReporter;
34
43
  class?: string;
35
- onsubmit?: (event: SubmitEvent) => void;
44
+ /** Return true only after the host has persisted this record successfully. */
45
+ onsubmit?: ObjectFormSubmitHandler;
36
46
  }
37
47
  declare const ObjectForm: Component<ObjectFormProps, {}, "value">;
38
48
  type ObjectForm = ReturnType<typeof ObjectForm>;
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectForm.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/ObjectForm.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AASrB,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAC7D,mFAAmF;IACnF,MAAM,CAAC,EAAE,yBAAyB,CAAC;IACnC,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,uEAAuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,6DAA6D;IAC7D,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CACzC;AAsSD,QAAA,MAAM,UAAU,yCAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ObjectForm.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/ObjectForm.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,qBAAqB,CAAC;AAU7B,MAAM,MAAM,+BAA+B,GAAG,OAAO,GAAG,IAAI,CAAC;AAC7D,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,WAAW,KACf,+BAA+B,GAAG,OAAO,CAAC,+BAA+B,CAAC,CAAC;AAEhF,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAC7D,mFAAmF;IACnF,MAAM,CAAC,EAAE,yBAAyB,CAAC;IACnC,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,uEAAuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,6DAA6D;IAC7D,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,uBAAuB,CAAC;CACpC;AAgXD,QAAA,MAAM,UAAU,yCAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -12,6 +12,21 @@
12
12
  * outside a Provider: an unwrapped field renders its children verbatim, and a
13
13
  * consumer can adopt the primitives incrementally without wrapping the whole
14
14
  * form.
15
+ *
16
+ * The two accessors are a deliberate two-tier contract, not a style choice:
17
+ *
18
+ * - `tryGetFieldPolicyContext` is for a primitive that still has something
19
+ * meaningful to render without a policy — today only `PolicyField`, whose
20
+ * fallback is the caller's own children.
21
+ * - `getFieldPolicyContext` is for the provider-only compositions
22
+ * (`ModeSwitch`, `AdvancedFields`, `FormHelp`) whose entire output is derived
23
+ * from the resolved policy. Degrading those would render an empty or absent
24
+ * control rather than surface the missing Provider, so they throw with an
25
+ * actionable message instead (#2272).
26
+ *
27
+ * One provider per form. `setContext` shadows, so a nested `FieldPolicyProvider`
28
+ * gives its subtree a second, independent `FieldPolicyModeStore` — consumers
29
+ * above the nested provider then stop tracking the `ModeSwitch` below it.
15
30
  */
16
31
  import type { ResolvedFieldPolicy, ResolvedObjectFieldPolicy } from '../types.js';
17
32
  /** UI display mode for progressive disclosure. */
@@ -1 +1 @@
1
- {"version":3,"file":"context.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/context.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EACV,mBAAmB,EACnB,yBAAyB,EAC1B,MAAM,aAAa,CAAC;AAErB,kDAAkD;AAClD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,UAAU,CAAC;AAEnD;;;;GAIG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,kBAAoC;gBAE/B,OAAO,GAAE,eAAyB;IAI9C,GAAG,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIhC,MAAM,IAAI,IAAI;CAGf;AAED,+EAA+E;AAC/E,MAAM,WAAW,uBAAuB;IACtC,gDAAgD;IAChD,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;IAC3C,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAAC;IAC7D,iEAAiE;IACjE,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AAID,2DAA2D;AAC3D,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAE5E;AAED,4DAA4D;AAC5D,wBAAgB,qBAAqB,IAAI,uBAAuB,CAS/D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IACpC,uBAAuB,GACvB,SAAS,CAIZ"}
1
+ {"version":3,"file":"context.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/context.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EACV,mBAAmB,EACnB,yBAAyB,EAC1B,MAAM,aAAa,CAAC;AAErB,kDAAkD;AAClD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,UAAU,CAAC;AAEnD;;;;GAIG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,kBAAoC;gBAE/B,OAAO,GAAE,eAAyB;IAI9C,GAAG,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIhC,MAAM,IAAI,IAAI;CAGf;AAED,+EAA+E;AAC/E,MAAM,WAAW,uBAAuB;IACtC,gDAAgD;IAChD,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;IAC3C,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAAC;IAC7D,iEAAiE;IACjE,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AAID,2DAA2D;AAC3D,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAE5E;AAED,4DAA4D;AAC5D,wBAAgB,qBAAqB,IAAI,uBAAuB,CAS/D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IACpC,uBAAuB,GACvB,SAAS,CAIZ"}
@@ -12,6 +12,21 @@
12
12
  * outside a Provider: an unwrapped field renders its children verbatim, and a
13
13
  * consumer can adopt the primitives incrementally without wrapping the whole
14
14
  * form.
15
+ *
16
+ * The two accessors are a deliberate two-tier contract, not a style choice:
17
+ *
18
+ * - `tryGetFieldPolicyContext` is for a primitive that still has something
19
+ * meaningful to render without a policy — today only `PolicyField`, whose
20
+ * fallback is the caller's own children.
21
+ * - `getFieldPolicyContext` is for the provider-only compositions
22
+ * (`ModeSwitch`, `AdvancedFields`, `FormHelp`) whose entire output is derived
23
+ * from the resolved policy. Degrading those would render an empty or absent
24
+ * control rather than surface the missing Provider, so they throw with an
25
+ * actionable message instead (#2272).
26
+ *
27
+ * One provider per form. `setContext` shadows, so a nested `FieldPolicyProvider`
28
+ * gives its subtree a second, independent `FieldPolicyModeStore` — consumers
29
+ * above the nested provider then stop tracking the `ModeSwitch` below it.
15
30
  */
16
31
  import { getContext, setContext } from 'svelte';
17
32
  /**
@@ -4,6 +4,8 @@ export interface FieldPolicyGearController {
4
4
  readonly error: string | null;
5
5
  readonly open: boolean;
6
6
  readonly canEdit: boolean;
7
+ /** Pending reviewed suggestions for this form's object, when configured. */
8
+ readonly pendingSuggestionCount: number;
7
9
  show(): void;
8
10
  hide(): void;
9
11
  reload(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"gear-context.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/gear-context.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAID,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,yBAAyB,GACpC,IAAI,CAEN;AAED,wBAAgB,yBAAyB,IAAI,yBAAyB,CAQrE;AAED,wBAAgB,4BAA4B,IACxC,yBAAyB,GACzB,SAAS,CAIZ"}
1
+ {"version":3,"file":"gear-context.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/gear-context.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,4EAA4E;IAC5E,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;IACxC,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAID,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,yBAAyB,GACpC,IAAI,CAEN;AAED,wBAAgB,yBAAyB,IAAI,yBAAyB,CAQrE;AAED,wBAAgB,4BAA4B,IACxC,yBAAyB,GACzB,SAAS,CAIZ"}
@@ -21,22 +21,25 @@ import FieldPolicyEditor from './components/FieldPolicyEditor.svelte';
21
21
  import FieldPolicyGearButton from './components/FieldPolicyGearButton.svelte';
22
22
  import FieldPolicyGearProvider from './components/FieldPolicyGearProvider.svelte';
23
23
  import FieldPolicyProvider from './components/FieldPolicyProvider.svelte';
24
+ import FieldPolicySuggestionQueue from './components/FieldPolicySuggestionQueue.svelte';
24
25
  import FormHelp from './components/FormHelp.svelte';
25
26
  import ModeSwitch from './components/ModeSwitch.svelte';
26
27
  import ObjectForm from './components/ObjectForm.svelte';
27
28
  import ObjectFormSourceProvider from './components/ObjectFormSourceProvider.svelte';
28
29
  import PolicyField from './components/PolicyField.svelte';
29
- export { AdvancedFields, FieldPolicyControlPanel, FieldPolicyEditor, FieldPolicyGearButton, FieldPolicyGearProvider, FieldPolicyProvider, FormHelp, ModeSwitch, ObjectForm, ObjectFormSourceProvider, PolicyField, };
30
+ export { AdvancedFields, FieldPolicyControlPanel, FieldPolicyEditor, FieldPolicyGearButton, FieldPolicyGearProvider, FieldPolicyProvider, FieldPolicySuggestionQueue, FormHelp, ModeSwitch, ObjectForm, ObjectFormSourceProvider, PolicyField, };
30
31
  export type AdvancedFieldsProps = ComponentProps<typeof AdvancedFields>;
31
32
  export type FieldPolicyProviderProps = ComponentProps<typeof FieldPolicyProvider>;
32
33
  export type FormHelpProps = ComponentProps<typeof FormHelp>;
33
34
  export type ModeSwitchProps = ComponentProps<typeof ModeSwitch>;
34
35
  export type ObjectFormProps = ComponentProps<typeof ObjectForm>;
36
+ export type { ObjectFormSubmitAcknowledgement, ObjectFormSubmitHandler, } from './components/ObjectForm.svelte';
35
37
  export type ObjectFormSourceProviderProps = ComponentProps<typeof ObjectFormSourceProvider>;
36
38
  export type FieldPolicyEditorProps = ComponentProps<typeof FieldPolicyEditor>;
37
39
  export type FieldPolicyControlPanelProps = ComponentProps<typeof FieldPolicyControlPanel>;
38
40
  export type FieldPolicyGearButtonProps = ComponentProps<typeof FieldPolicyGearButton>;
39
41
  export type FieldPolicyGearProviderProps = ComponentProps<typeof FieldPolicyGearProvider>;
42
+ export type FieldPolicySuggestionQueueProps = ComponentProps<typeof FieldPolicySuggestionQueue>;
40
43
  export type PolicyFieldProps = ComponentProps<typeof PolicyField>;
41
44
  export type { FieldPolicyCatalogObjectSummary, FieldPolicyDetailItem, FieldPolicySettingsCatalogData, FieldPolicySettingsCatalogPage, FieldPolicySummaryItem, } from '../settings-catalog.js';
42
45
  export type { ResolvedFieldPolicy, ResolvedObjectFieldPolicy, } from '../types.js';
@@ -54,5 +57,7 @@ export { resolveObjectFormFields } from './object-form.js';
54
57
  export { assertObjectFormCollectionDefinition, ObjectFormSourceRegistry, } from './object-form-source.svelte.js';
55
58
  export type { FieldPolicyControlPanelAdapter, FieldPolicyFieldRollup, FieldPolicyLayerCell, } from './settings-catalog.js';
56
59
  export { auditObjectRefs, decorateCatalogItem, decorateCatalogPage, fieldPolicyControlPanelNavItem, fieldPolicyRollup, MAX_FIELD_POLICY_AUDIT_OBJECT_REFS, orgRowIdsForObject, prunableDriftRows, } from './settings-catalog.js';
60
+ export { type FieldPolicySuggestion, type FieldPolicySuggestionAdapter, type FieldPolicySuggestionKind, fieldPolicySuggestionEvidence, parsePendingFieldPolicySuggestions, } from './suggestions.js';
57
61
  export type { FieldInputProps, ObjectFormCollectionDefinition, ObjectFormField, ObjectFormFieldDefinition, ObjectFormFieldSnippetProps, ObjectFormPolicyClient, ObjectFormResolvedSource, ObjectFormSource, ObjectFormWireType, PolicyFieldSnippetProps, } from './types.js';
62
+ export { type CollectFieldUsageEntriesOptions, canCaptureFieldUsageValue, collectFieldUsageEntries, type FieldUsageDefault, type FieldUsageEntry, type FieldUsageReporter, type FieldUsageWireType, fieldUsageValuesEqual, isBlankFieldValue, reportFieldUsage, } from './usage-capture.js';
58
63
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/svelte/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/svelte/index.ts"],"names":[],"mappings":"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"}
@@ -20,13 +20,14 @@ import FieldPolicyEditor from './components/FieldPolicyEditor.svelte';
20
20
  import FieldPolicyGearButton from './components/FieldPolicyGearButton.svelte';
21
21
  import FieldPolicyGearProvider from './components/FieldPolicyGearProvider.svelte';
22
22
  import FieldPolicyProvider from './components/FieldPolicyProvider.svelte';
23
+ import FieldPolicySuggestionQueue from './components/FieldPolicySuggestionQueue.svelte';
23
24
  import FormHelp from './components/FormHelp.svelte';
24
25
  import ModeSwitch from './components/ModeSwitch.svelte';
25
26
  import ObjectForm from './components/ObjectForm.svelte';
26
27
  import ObjectFormSourceProvider from './components/ObjectFormSourceProvider.svelte';
27
28
  import PolicyField from './components/PolicyField.svelte';
28
29
  // Components
29
- export { AdvancedFields, FieldPolicyControlPanel, FieldPolicyEditor, FieldPolicyGearButton, FieldPolicyGearProvider, FieldPolicyProvider, FormHelp, ModeSwitch, ObjectForm, ObjectFormSourceProvider, PolicyField, };
30
+ export { AdvancedFields, FieldPolicyControlPanel, FieldPolicyEditor, FieldPolicyGearButton, FieldPolicyGearProvider, FieldPolicyProvider, FieldPolicySuggestionQueue, FormHelp, ModeSwitch, ObjectForm, ObjectFormSourceProvider, PolicyField, };
30
31
  // Context types and accessors
31
32
  export { getFieldPolicyContext, setFieldPolicyContext, tryGetFieldPolicyContext, } from './context.svelte.js';
32
33
  export { policyToVisibleColumnIds } from './data-table.js';
@@ -36,3 +37,5 @@ export { createFieldInputRegistry, FieldInputRegistry, } from './input-registry.
36
37
  export { resolveObjectFormFields } from './object-form.js';
37
38
  export { assertObjectFormCollectionDefinition, ObjectFormSourceRegistry, } from './object-form-source.svelte.js';
38
39
  export { auditObjectRefs, decorateCatalogItem, decorateCatalogPage, fieldPolicyControlPanelNavItem, fieldPolicyRollup, MAX_FIELD_POLICY_AUDIT_OBJECT_REFS, orgRowIdsForObject, prunableDriftRows, } from './settings-catalog.js';
40
+ export { fieldPolicySuggestionEvidence, parsePendingFieldPolicySuggestions, } from './suggestions.js';
41
+ export { canCaptureFieldUsageValue, collectFieldUsageEntries, fieldUsageValuesEqual, isBlankFieldValue, reportFieldUsage, } from './usage-capture.js';
@@ -97,19 +97,25 @@ function handleSubmit() {
97
97
  </script>
98
98
 
99
99
  <section class="field-policy-preview">
100
- <header class="preview-header">
101
- <h2>Hand-written form adopting PolicyField</h2>
102
- <p class="preview-desc">
103
- A developer-authored product form. Two fields (name, SKU) adopt
104
- PolicyField for help, defaults, and progressive disclosure; the rest stay
105
- hand-written. Toggle the mode switch to reveal advanced-tier fields.
106
- </p>
107
- <FormHelp
108
- objectDescription="A sellable catalog product with wholesale pricing and inventory controls."
109
- />
110
- </header>
111
-
100
+ <!--
101
+ ONE provider, extended over the header too. FormHelp assembles its glossary
102
+ from the provider context and must live inside it; the provider renders no
103
+ markup of its own, so covering the header costs no layout. Do not add a
104
+ second provider to reach it a nested one shadows this mode store — #2272.
105
+ -->
112
106
  <FieldPolicyProvider policy={resolvedPolicy} mode="basic">
107
+ <header class="preview-header">
108
+ <h2>Hand-written form adopting PolicyField</h2>
109
+ <p class="preview-desc">
110
+ A developer-authored product form. Two fields (name, SKU) adopt
111
+ PolicyField for help, defaults, and progressive disclosure; the rest stay
112
+ hand-written. Toggle the mode switch to reveal advanced-tier fields.
113
+ </p>
114
+ <FormHelp
115
+ objectDescription="A sellable catalog product with wholesale pricing and inventory controls."
116
+ />
117
+ </header>
118
+
113
119
  <div class="toolbar">
114
120
  <ModeSwitch />
115
121
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"FieldPolicyFormPreview.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/playground/FieldPolicyFormPreview.svelte.ts"],"names":[],"mappings":"AAqKA,QAAA,MAAM,sBAAsB,2DAAwC,CAAC;AACrE,KAAK,sBAAsB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACxE,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"FieldPolicyFormPreview.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/playground/FieldPolicyFormPreview.svelte.ts"],"names":[],"mappings":"AAsKA,QAAA,MAAM,sBAAsB,2DAAwC,CAAC;AACrE,KAAK,sBAAsB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACxE,eAAe,sBAAsB,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Structural browser contracts for field-policy suggestion review.
3
+ *
4
+ * These types intentionally omit tenant, user, authorization, and field
5
+ * sensitivity data. Hosts bind methods to authenticated generated clients;
6
+ * the server derives identity and validates every action.
7
+ */
8
+ export type FieldPolicySuggestionKind = 'promote' | 'default';
9
+ export interface FieldPolicySuggestion {
10
+ id: string;
11
+ objectRef: string;
12
+ fieldName: string;
13
+ kind: FieldPolicySuggestionKind;
14
+ proposedValue: string | null;
15
+ evidence: Readonly<Record<string, unknown>>;
16
+ }
17
+ export interface FieldPolicySuggestionAdapter {
18
+ pendingSuggestions(input?: {
19
+ objectRefs?: readonly string[];
20
+ }): Promise<unknown>;
21
+ acceptSuggestion(input: {
22
+ id: string;
23
+ }): Promise<unknown>;
24
+ dismissSuggestion(input: {
25
+ id: string;
26
+ }): Promise<unknown>;
27
+ }
28
+ /**
29
+ * Validate generated custom-action output at the browser boundary. A malformed
30
+ * response is an error, never an empty queue that could conceal work.
31
+ */
32
+ export declare function parsePendingFieldPolicySuggestions(value: unknown): {
33
+ suggestions: FieldPolicySuggestion[];
34
+ total: number;
35
+ };
36
+ /** Human-readable evidence without assuming a server-side evidence schema. */
37
+ export declare function fieldPolicySuggestionEvidence(suggestion: FieldPolicySuggestion): string;
38
+ //# sourceMappingURL=suggestions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggestions.d.ts","sourceRoot":"","sources":["../../src/svelte/suggestions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,yBAAyB,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,yBAAyB,CAAC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,4BAA4B;IAC3C,kBAAkB,CAAC,KAAK,CAAC,EAAE;QACzB,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;KAChC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrB,gBAAgB,CAAC,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,iBAAiB,CAAC,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5D;AAED;;;GAGG;AACH,wBAAgB,kCAAkC,CAAC,KAAK,EAAE,OAAO,GAAG;IAClE,WAAW,EAAE,qBAAqB,EAAE,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;CACf,CAsBA;AAmCD,8EAA8E;AAC9E,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,qBAAqB,GAChC,MAAM,CASR"}