@happyvertical/smrt-fields 0.40.60 → 0.40.61

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 (184) hide show
  1. package/AGENTS.md +58 -12
  2. package/README.md +90 -2
  3. package/dist/__smrt-register__.d.ts +2 -0
  4. package/dist/__smrt-register__.d.ts.map +1 -0
  5. package/dist/cache.d.ts +18 -0
  6. package/dist/cache.d.ts.map +1 -0
  7. package/dist/collections/FieldPolicyCollection.d.ts +95 -0
  8. package/dist/collections/FieldPolicyCollection.d.ts.map +1 -0
  9. package/dist/field-definitions.d.ts +77 -0
  10. package/dist/field-definitions.d.ts.map +1 -0
  11. package/dist/field-policy-resolver.d.ts +46 -0
  12. package/dist/field-policy-resolver.d.ts.map +1 -0
  13. package/dist/index.d.ts +9 -532
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +752 -55
  16. package/dist/index.js.map +1 -1
  17. package/dist/manifest.json +45 -3
  18. package/dist/models/FieldPolicy.d.ts +163 -0
  19. package/dist/models/FieldPolicy.d.ts.map +1 -0
  20. package/dist/permissions.d.ts +9 -0
  21. package/dist/permissions.d.ts.map +1 -0
  22. package/dist/playground.d.ts +2 -0
  23. package/dist/playground.d.ts.map +1 -0
  24. package/dist/playground.js +39 -0
  25. package/dist/playground.js.map +1 -0
  26. package/dist/settings-catalog.d.ts +73 -0
  27. package/dist/settings-catalog.d.ts.map +1 -0
  28. package/dist/smrt-knowledge.json +50 -7
  29. package/dist/svelte/__tests__/FieldPolicyControlPanel.test.js +223 -0
  30. package/dist/svelte/__tests__/FieldPolicyGear.test.js +503 -0
  31. package/dist/svelte/__tests__/FormHelp.test.js +138 -0
  32. package/dist/svelte/__tests__/ModeUX.test.js +109 -0
  33. package/dist/svelte/__tests__/ObjectForm.test.js +556 -0
  34. package/dist/svelte/__tests__/ObjectFormGeneratedApi.integration.test.js +436 -0
  35. package/dist/svelte/__tests__/PolicyField.test.js +373 -0
  36. package/dist/svelte/__tests__/fixtures/AdvancedFieldsFixture.svelte +30 -0
  37. package/dist/svelte/__tests__/fixtures/AdvancedFieldsFixture.svelte.d.ts +9 -0
  38. package/dist/svelte/__tests__/fixtures/AdvancedFieldsFixture.svelte.d.ts.map +1 -0
  39. package/dist/svelte/__tests__/fixtures/DomPrefillFixture.svelte +33 -0
  40. package/dist/svelte/__tests__/fixtures/DomPrefillFixture.svelte.d.ts +10 -0
  41. package/dist/svelte/__tests__/fixtures/DomPrefillFixture.svelte.d.ts.map +1 -0
  42. package/dist/svelte/__tests__/fixtures/FormHelpFixture.svelte +19 -0
  43. package/dist/svelte/__tests__/fixtures/FormHelpFixture.svelte.d.ts +10 -0
  44. package/dist/svelte/__tests__/fixtures/FormHelpFixture.svelte.d.ts.map +1 -0
  45. package/dist/svelte/__tests__/fixtures/GeneratedApiGearFixture.svelte +18 -0
  46. package/dist/svelte/__tests__/fixtures/GeneratedApiGearFixture.svelte.d.ts +11 -0
  47. package/dist/svelte/__tests__/fixtures/GeneratedApiGearFixture.svelte.d.ts.map +1 -0
  48. package/dist/svelte/__tests__/fixtures/GracefulDegradeFixture.svelte +11 -0
  49. package/dist/svelte/__tests__/fixtures/GracefulDegradeFixture.svelte.d.ts +19 -0
  50. package/dist/svelte/__tests__/fixtures/GracefulDegradeFixture.svelte.d.ts.map +1 -0
  51. package/dist/svelte/__tests__/fixtures/ModeSwitchFixture.svelte +18 -0
  52. package/dist/svelte/__tests__/fixtures/ModeSwitchFixture.svelte.d.ts +8 -0
  53. package/dist/svelte/__tests__/fixtures/ModeSwitchFixture.svelte.d.ts.map +1 -0
  54. package/dist/svelte/__tests__/fixtures/NoIdFixture.svelte +24 -0
  55. package/dist/svelte/__tests__/fixtures/NoIdFixture.svelte.d.ts +13 -0
  56. package/dist/svelte/__tests__/fixtures/NoIdFixture.svelte.d.ts.map +1 -0
  57. package/dist/svelte/__tests__/fixtures/ObjectFormActionsFixture.svelte +20 -0
  58. package/dist/svelte/__tests__/fixtures/ObjectFormActionsFixture.svelte.d.ts +11 -0
  59. package/dist/svelte/__tests__/fixtures/ObjectFormActionsFixture.svelte.d.ts.map +1 -0
  60. package/dist/svelte/__tests__/fixtures/ObjectFormFixture.svelte +17 -0
  61. package/dist/svelte/__tests__/fixtures/ObjectFormFixture.svelte.d.ts +10 -0
  62. package/dist/svelte/__tests__/fixtures/ObjectFormFixture.svelte.d.ts.map +1 -0
  63. package/dist/svelte/__tests__/fixtures/ObjectFormRegistryFixture.svelte +25 -0
  64. package/dist/svelte/__tests__/fixtures/ObjectFormRegistryFixture.svelte.d.ts +10 -0
  65. package/dist/svelte/__tests__/fixtures/ObjectFormRegistryFixture.svelte.d.ts.map +1 -0
  66. package/dist/svelte/__tests__/fixtures/ObjectFormSnippetFixture.svelte +34 -0
  67. package/dist/svelte/__tests__/fixtures/ObjectFormSnippetFixture.svelte.d.ts +10 -0
  68. package/dist/svelte/__tests__/fixtures/ObjectFormSnippetFixture.svelte.d.ts.map +1 -0
  69. package/dist/svelte/__tests__/fixtures/ObjectFormSourceFixture.svelte +29 -0
  70. package/dist/svelte/__tests__/fixtures/ObjectFormSourceFixture.svelte.d.ts +11 -0
  71. package/dist/svelte/__tests__/fixtures/ObjectFormSourceFixture.svelte.d.ts.map +1 -0
  72. package/dist/svelte/__tests__/fixtures/ObjectFormSourceSnippetFixture.svelte +33 -0
  73. package/dist/svelte/__tests__/fixtures/ObjectFormSourceSnippetFixture.svelte.d.ts +9 -0
  74. package/dist/svelte/__tests__/fixtures/ObjectFormSourceSnippetFixture.svelte.d.ts.map +1 -0
  75. package/dist/svelte/__tests__/fixtures/PolicyDataTableFixture.svelte +40 -0
  76. package/dist/svelte/__tests__/fixtures/PolicyDataTableFixture.svelte.d.ts +8 -0
  77. package/dist/svelte/__tests__/fixtures/PolicyDataTableFixture.svelte.d.ts.map +1 -0
  78. package/dist/svelte/__tests__/fixtures/PrefillFixture.svelte +26 -0
  79. package/dist/svelte/__tests__/fixtures/PrefillFixture.svelte.d.ts +13 -0
  80. package/dist/svelte/__tests__/fixtures/PrefillFixture.svelte.d.ts.map +1 -0
  81. package/dist/svelte/__tests__/fixtures/ProviderFieldFixture.svelte +39 -0
  82. package/dist/svelte/__tests__/fixtures/ProviderFieldFixture.svelte.d.ts +17 -0
  83. package/dist/svelte/__tests__/fixtures/ProviderFieldFixture.svelte.d.ts.map +1 -0
  84. package/dist/svelte/__tests__/fixtures/RegistryInput.svelte +15 -0
  85. package/dist/svelte/__tests__/fixtures/RegistryInput.svelte.d.ts +5 -0
  86. package/dist/svelte/__tests__/fixtures/RegistryInput.svelte.d.ts.map +1 -0
  87. package/dist/svelte/__tests__/fixtures/RevealPrefillFixture.svelte +29 -0
  88. package/dist/svelte/__tests__/fixtures/RevealPrefillFixture.svelte.d.ts +14 -0
  89. package/dist/svelte/__tests__/fixtures/RevealPrefillFixture.svelte.d.ts.map +1 -0
  90. package/dist/svelte/__tests__/fixtures/SettingsCatalogStub.svelte +24 -0
  91. package/dist/svelte/__tests__/fixtures/SettingsCatalogStub.svelte.d.ts +14 -0
  92. package/dist/svelte/__tests__/fixtures/SettingsCatalogStub.svelte.d.ts.map +1 -0
  93. package/dist/svelte/__tests__/fixtures/SnippetFixture.svelte +28 -0
  94. package/dist/svelte/__tests__/fixtures/SnippetFixture.svelte.d.ts +13 -0
  95. package/dist/svelte/__tests__/fixtures/SnippetFixture.svelte.d.ts.map +1 -0
  96. package/dist/svelte/__tests__/fixtures/ToggleModeButton.svelte +14 -0
  97. package/dist/svelte/__tests__/fixtures/ToggleModeButton.svelte.d.ts +19 -0
  98. package/dist/svelte/__tests__/fixtures/ToggleModeButton.svelte.d.ts.map +1 -0
  99. package/dist/svelte/__tests__/fixtures/TooltipFixture.svelte +25 -0
  100. package/dist/svelte/__tests__/fixtures/TooltipFixture.svelte.d.ts +14 -0
  101. package/dist/svelte/__tests__/fixtures/TooltipFixture.svelte.d.ts.map +1 -0
  102. package/dist/svelte/__tests__/settings-catalog.test.js +161 -0
  103. package/dist/svelte/components/AdvancedFields.svelte +49 -0
  104. package/dist/svelte/components/AdvancedFields.svelte.d.ts +17 -0
  105. package/dist/svelte/components/AdvancedFields.svelte.d.ts.map +1 -0
  106. package/dist/svelte/components/FieldInput.svelte +159 -0
  107. package/dist/svelte/components/FieldInput.svelte.d.ts +5 -0
  108. package/dist/svelte/components/FieldInput.svelte.d.ts.map +1 -0
  109. package/dist/svelte/components/FieldPolicyControlPanel.svelte +261 -0
  110. package/dist/svelte/components/FieldPolicyControlPanel.svelte.d.ts +26 -0
  111. package/dist/svelte/components/FieldPolicyControlPanel.svelte.d.ts.map +1 -0
  112. package/dist/svelte/components/FieldPolicyEditor.svelte +417 -0
  113. package/dist/svelte/components/FieldPolicyEditor.svelte.d.ts +18 -0
  114. package/dist/svelte/components/FieldPolicyEditor.svelte.d.ts.map +1 -0
  115. package/dist/svelte/components/FieldPolicyGearButton.svelte +17 -0
  116. package/dist/svelte/components/FieldPolicyGearButton.svelte.d.ts +8 -0
  117. package/dist/svelte/components/FieldPolicyGearButton.svelte.d.ts.map +1 -0
  118. package/dist/svelte/components/FieldPolicyGearProvider.svelte +135 -0
  119. package/dist/svelte/components/FieldPolicyGearProvider.svelte.d.ts +17 -0
  120. package/dist/svelte/components/FieldPolicyGearProvider.svelte.d.ts.map +1 -0
  121. package/dist/svelte/components/FieldPolicyProvider.svelte +89 -0
  122. package/dist/svelte/components/FieldPolicyProvider.svelte.d.ts +35 -0
  123. package/dist/svelte/components/FieldPolicyProvider.svelte.d.ts.map +1 -0
  124. package/dist/svelte/components/FormHelp.svelte +157 -0
  125. package/dist/svelte/components/FormHelp.svelte.d.ts +15 -0
  126. package/dist/svelte/components/FormHelp.svelte.d.ts.map +1 -0
  127. package/dist/svelte/components/ModeSwitch.svelte +47 -0
  128. package/dist/svelte/components/ModeSwitch.svelte.d.ts +10 -0
  129. package/dist/svelte/components/ModeSwitch.svelte.d.ts.map +1 -0
  130. package/dist/svelte/components/ObjectForm.svelte +351 -0
  131. package/dist/svelte/components/ObjectForm.svelte.d.ts +40 -0
  132. package/dist/svelte/components/ObjectForm.svelte.d.ts.map +1 -0
  133. package/dist/svelte/components/ObjectFormSourceProvider.svelte +18 -0
  134. package/dist/svelte/components/ObjectFormSourceProvider.svelte.d.ts +11 -0
  135. package/dist/svelte/components/ObjectFormSourceProvider.svelte.d.ts.map +1 -0
  136. package/dist/svelte/components/PolicyField.svelte +338 -0
  137. package/dist/svelte/components/PolicyField.svelte.d.ts +80 -0
  138. package/dist/svelte/components/PolicyField.svelte.d.ts.map +1 -0
  139. package/dist/svelte/context.svelte.d.ts +54 -0
  140. package/dist/svelte/context.svelte.d.ts.map +1 -0
  141. package/dist/svelte/context.svelte.js +55 -0
  142. package/dist/svelte/data-table.d.ts +17 -0
  143. package/dist/svelte/data-table.d.ts.map +1 -0
  144. package/dist/svelte/data-table.js +19 -0
  145. package/dist/svelte/field-policy-editor.d.ts +81 -0
  146. package/dist/svelte/field-policy-editor.d.ts.map +1 -0
  147. package/dist/svelte/field-policy-editor.js +120 -0
  148. package/dist/svelte/gear-context.svelte.d.ts +14 -0
  149. package/dist/svelte/gear-context.svelte.d.ts.map +1 -0
  150. package/dist/svelte/gear-context.svelte.js +15 -0
  151. package/dist/svelte/index.d.ts +58 -0
  152. package/dist/svelte/index.d.ts.map +1 -0
  153. package/dist/svelte/index.js +38 -0
  154. package/dist/svelte/input-registry.d.ts +21 -0
  155. package/dist/svelte/input-registry.d.ts.map +1 -0
  156. package/dist/svelte/input-registry.js +26 -0
  157. package/dist/svelte/object-form-source-context.svelte.d.ts +4 -0
  158. package/dist/svelte/object-form-source-context.svelte.d.ts.map +1 -0
  159. package/dist/svelte/object-form-source-context.svelte.js +8 -0
  160. package/dist/svelte/object-form-source.svelte.d.ts +18 -0
  161. package/dist/svelte/object-form-source.svelte.d.ts.map +1 -0
  162. package/dist/svelte/object-form-source.svelte.js +99 -0
  163. package/dist/svelte/object-form.d.ts +6 -0
  164. package/dist/svelte/object-form.d.ts.map +1 -0
  165. package/dist/svelte/object-form.js +38 -0
  166. package/dist/svelte/playground/FieldPolicyFormPreview.svelte +212 -0
  167. package/dist/svelte/playground/FieldPolicyFormPreview.svelte.d.ts +4 -0
  168. package/dist/svelte/playground/FieldPolicyFormPreview.svelte.d.ts.map +1 -0
  169. package/dist/svelte/playground/ObjectFormPreview.svelte +129 -0
  170. package/dist/svelte/playground/ObjectFormPreview.svelte.d.ts +4 -0
  171. package/dist/svelte/playground/ObjectFormPreview.svelte.d.ts.map +1 -0
  172. package/dist/svelte/playground.d.ts +20 -0
  173. package/dist/svelte/playground.d.ts.map +1 -0
  174. package/dist/svelte/playground.js +38 -0
  175. package/dist/svelte/settings-catalog.d.ts +54 -0
  176. package/dist/svelte/settings-catalog.d.ts.map +1 -0
  177. package/dist/svelte/settings-catalog.js +116 -0
  178. package/dist/svelte/types.d.ts +101 -0
  179. package/dist/svelte/types.d.ts.map +1 -0
  180. package/dist/svelte/types.js +4 -0
  181. package/dist/types.d.ts +276 -203
  182. package/dist/types.d.ts.map +1 -0
  183. package/dist/types.js.map +1 -1
  184. package/package.json +33 -8
package/AGENTS.md CHANGED
@@ -36,9 +36,11 @@ per-field `{defaultValue, visibility, help, label, order, locked}` for any
36
36
  2. App rows — `scopeType: 'app'`, `tenantId`/`userId` null
37
37
  3. Tenant rows — hierarchy walk root → leaf via an injected
38
38
  `tenantHierarchyLoader` (smrt-features shape); the default loader
39
- dynamic-imports `@happyvertical/smrt-users` (missing-package failures
40
- `ERR_MODULE_NOT_FOUND` / "Cannot find package" across the cause chain
41
- fall back to a flat single-tenant chain). A node that breaks permission
39
+ uses `@happyvertical/smrt-users`' `TenantCollection`; an injected loader
40
+ may return no provider (or no chain for a tenant), which falls back to a
41
+ flat single-tenant chain. `smrt-users` itself is a required Fields runtime
42
+ dependency for policy authorization, not an optional hierarchy dependency.
43
+ A node that breaks permission
42
44
  inheritance discards every earlier tenant contribution (chain-structural),
43
45
  so only the suffix from the LAST break participates — in merging AND in
44
46
  the explained layers, which therefore replay to the merged result
@@ -75,9 +77,11 @@ per-field `{defaultValue, visibility, help, label, order, locked}` for any
75
77
  - **Write-time org checks reuse the resolver**: the required-demotion default
76
78
  and the user-write lock are computed by `resolveFieldPolicy` over the org
77
79
  tiers (default hierarchy loader), so cascading ancestor-tenant defaults and
78
- locks are honored at save time too. On updates the resolver sees the row's
79
- persisted version (no self-exclusion), so the resolver-side safety net
80
- remains the authoritative enforcement at read time.
80
+ locks are honored at save time too. On updates the persisted row is excluded
81
+ from projected lower-layer resolution, so clearing the row's only default
82
+ while demoting a required field is rejected before mutation; that projected
83
+ lookup bypasses the shared cache. The resolver-side safety net remains
84
+ authoritative when a different row is later deleted.
81
85
  - **Isolation — a MISSING identity component DENIES, it never skips.** This
82
86
  is the package rule; both the write guard
83
87
  (`FieldPolicy.assertScopeOwnedByAmbientContext`) and the read guard
@@ -88,12 +92,13 @@ per-field `{defaultValue, visibility, help, label, order, locked}` for any
88
92
  `withTenant({ tenantId })`) may not touch the user tier at all. Skipping
89
93
  that check instead of denying it was a live ownership bypass: user rows are
90
94
  `tenantId: null` by design, so nothing else contains such a write. App-scope
91
- writes inside a tenant context require super-admin bypass. With NO ambient
92
- identity at all (tenancy ALS never entered), only app-scope writes/deletes
93
- are accepted; context-LESS *reads* stay allowed because
94
- `resolveFieldPolicy` is a trusted server-side API. Residual: ALS-less
95
- deployments can still write APP rows with any authenticated principal until
96
- the #2049 permission layer adds `fields:policy:manage`. `save()`/`delete()`
95
+ writes inside a tenant context require super-admin bypass. `fields.policy.manage`
96
+ authorizes app/tenant policy mutations; `fields.policy.personalize` authorizes
97
+ only the caller's user tier (default-seeded for built-in roles). With NO ambient
98
+ identity at all (tenancy ALS never entered), policy writes/deletes fail closed;
99
+ trusted system and super-admin contexts retain their explicit bypasses.
100
+ Context-LESS *reads* stay allowed because `resolveFieldPolicy` is a trusted
101
+ server-side API. `save()`/`delete()`
97
102
  on an existing row additionally authorize against the row's PERSISTED
98
103
  scope, looked up by primary key AND — because a generated create always
99
104
  mints a fresh UUID while the `conflictColumns` upsert still replaces the
@@ -171,6 +176,47 @@ per-field `{defaultValue, visibility, help, label, order, locked}` for any
171
176
  (`_smrt_field_policies`), and both are pinned in
172
177
  `generated-surfaces.test.ts`.
173
178
 
179
+ ## Svelte generated forms (#2049)
180
+
181
+ - `ObjectForm` accepts direct generated `fields` plus a resolved `policy` for
182
+ SSR and explicit hosts, or accepts only `objectRef` beneath an
183
+ `ObjectFormSourceProvider`. `ObjectFormSourceRegistry` is per app and maps
184
+ canonical refs to generated web collection definitions before calling the
185
+ generated `resolveBatch` custom action. It uses structural types only: this
186
+ package must never import `smrt-web`.
187
+ - Generated custom-action clients resolve `Promise<any>`; validate their
188
+ `policies[objectRef]` response at the registry boundary and fail closed on a
189
+ missing/mismatched definition or policy. The component renders an accessible
190
+ loading state and alert rather than a partial form.
191
+ - Browser manifest types are `text`, `integer`, `decimal`, `boolean`,
192
+ `datetime`, `json`, `foreignKey`, and `crossPackageRef`; there is no `select`
193
+ wire type. Apps use the per-app `FieldInputRegistry.registerField` seam for
194
+ select-like widgets. Reference fields intentionally default to identifier
195
+ inputs unless an app supplies a chooser.
196
+ - `policyToVisibleColumnIds(policy, columns)` feeds smrt-ui `DataTable`'s
197
+ `visibleColumnIds`; it filters policy-hidden mapped fields, preserves unmapped
198
+ computed/action columns, and cannot reveal a static `column.hidden` column.
199
+
200
+ ## Defaults control panel (#2050)
201
+
202
+ - `buildFieldPolicySettingsCatalog()` is the server-side, URL/GET-driven
203
+ catalog builder. It structurally targets `SettingsCatalog`, but this package
204
+ must not import `smrt-svelte`; hosts inject `SettingsCatalog` into
205
+ `FieldPolicyControlPanel` and retain their own route and transport adapters.
206
+ - `policyAudit` is the only routed organization roll-up. It requires
207
+ `fields.policy.manage`, returns only the caller tenant's editable rows and
208
+ read-only app summaries, and represents other users strictly as per-field
209
+ counts. It resolves only requested page refs; never pre-resolve the catalog.
210
+ - Display code/app/org values by replaying the explained resolver layers, not
211
+ by independently calculating precedence. Reset and drift prune are ordinary
212
+ model deletes, so existing scope/permission validation remains authoritative.
213
+ The panel asks for an explicit confirmation before either destructive action;
214
+ SSR hosts can inject that confirmation decision instead of relying on
215
+ `window.confirm`.
216
+ - `fieldPolicyControlPanelNavItem()` is a structural AdminShell tenant-nav
217
+ seam. It never imports `smrt-svelte` or `smrt-web`; the host supplies the
218
+ returned entry and must enforce its real route permission server-side.
219
+
174
220
  ## Related
175
221
 
176
222
  - `@happyvertical/smrt-prompts` / `smrt-languages` / `smrt-features` — the
package/README.md CHANGED
@@ -39,10 +39,15 @@ const explained = await resolveFieldPolicyExplained(
39
39
  ```
40
40
 
41
41
  Resolution layers (low → high): code seed → app rows → tenant rows
42
- (hierarchy walk via an optional `tenantHierarchyLoader`; flat fallback
43
- without `@happyvertical/smrt-users`) → user rows. A NULL column inherits
42
+ (hierarchy walk via the users tenant loader, or a flat fallback when an
43
+ injected hierarchy provider cannot resolve the tenant) → user rows. A NULL column inherits
44
44
  from the lower layer; resetting a customization is a row delete.
45
45
 
46
+ `@happyvertical/smrt-users` is a required runtime dependency: Field Policy
47
+ uses its permission catalog and operation guard for every write and gear
48
+ action. The hierarchy fallback concerns tenant ancestry only; it is not a
49
+ users-authorization fallback.
50
+
46
51
  Writes are validated against the live `ObjectRegistry`: unknown
47
52
  objects/fields are rejected, defaults are type-checked, and defaults on
48
53
  `transient`/`sensitive`/`readPermission`-gated fields are refused. Required
@@ -50,3 +55,86 @@ fields can only be demoted from `basic` when a usable default resolves —
50
55
  and the resolver re-enforces that invariant at read time.
51
56
 
52
57
  See `AGENTS.md` for the full architecture notes.
58
+
59
+ ## Svelte ObjectForm
60
+
61
+ `@happyvertical/smrt-fields/svelte` provides provider-free generated forms.
62
+ Pass only the generated browser field definitions and the matching resolved
63
+ policy; `ObjectForm` renders their safe intersection, honors policy visibility
64
+ and ordering, and keeps form state transport-neutral.
65
+
66
+ ```svelte
67
+ <script lang="ts">
68
+ import { ObjectForm, createFieldInputRegistry } from '@happyvertical/smrt-fields/svelte';
69
+
70
+ const inputRegistry = createFieldInputRegistry();
71
+ // inputRegistry.registerField(objectRef, 'body', RichTextInput);
72
+ </script>
73
+
74
+ <ObjectForm {objectRef} fields={collectionDefinition.fields} {policy}
75
+ bind:value={record} {inputRegistry} />
76
+ ```
77
+
78
+ Pass an `actions` snippet to place host controls inside the owned native form.
79
+ The snippet renders after ObjectForm's policy-ordered fields, so a regular
80
+ submit button keeps native Enter/click submission and ObjectForm's validation
81
+ and `onsubmit` handling without querying the DOM.
82
+
83
+ ```svelte
84
+ <ObjectForm {objectRef} fields={collectionDefinition.fields} {policy}
85
+ bind:value={record} onsubmit={save}>
86
+ {#snippet actions()}
87
+ <button type="submit">Save</button>
88
+ {/snippet}
89
+ </ObjectForm>
90
+ ```
91
+
92
+ An app can register all of its generated collection definitions once and put
93
+ the `resolveBatch` custom-action client behind an `ObjectFormSourceProvider`.
94
+ Then forms need only their canonical object reference; the registry validates
95
+ the generated definition and the untyped custom-action response before it is
96
+ rendered, failing closed with an accessible error state on a missing or
97
+ mismatched response.
98
+
99
+ ```svelte
100
+ <script lang="ts">
101
+ import {
102
+ ObjectForm,
103
+ ObjectFormSourceProvider,
104
+ ObjectFormSourceRegistry,
105
+ } from '@happyvertical/smrt-fields/svelte';
106
+
107
+ const source = new ObjectFormSourceRegistry(fieldPoliciesClient);
108
+ for (const definition of Object.values(collectionDefinitions)) source.register(definition);
109
+ </script>
110
+
111
+ <ObjectFormSourceProvider {source}>
112
+ <ObjectForm objectRef="@happyvertical/smrt-products:Product" bind:value={record} />
113
+ </ObjectFormSourceProvider>
114
+ ```
115
+
116
+ The built-ins support text, integer, decimal, boolean, datetime, JSON, and
117
+ reference identifiers. `FieldInputRegistry` is per app: a field-specific
118
+ renderer takes precedence over a wire-type renderer. SMRT has no `select` wire
119
+ type: keep the persisted wire type (normally `text`) and register a
120
+ field-specific select-like renderer with `registerField(objectRef, fieldName,
121
+ component)`. Reference fields deliberately remain provider-free identifier
122
+ inputs unless an app registers its own chooser. `policyToVisibleColumnIds`
123
+ adapts the same resolved policy to `DataTable` without hiding unmapped action or
124
+ computed columns; static `column.hidden` remains authoritative.
125
+
126
+ When a mounted create form starts another record, replace the bound record with
127
+ an empty object or change `createSessionKey`; both begin a new default-prefill
128
+ session without reapplying defaults after an in-form user clear.
129
+
130
+ ## Policy settings gear
131
+
132
+ `FieldPolicyGearProvider` makes the context-derived `editor-state` action
133
+ available to any policy-aware form without choosing a client transport. Pass an
134
+ adapter around the generated collection client's `getEditorState`, `create`,
135
+ `update`, and `delete` calls; it must not accept tenant or user identifiers.
136
+ Use `FieldPolicyGearButton` where the form wants its affordance, or set
137
+ `showPolicyGear` on `ObjectForm`. `registerFieldPolicyFocusTool(shell,
138
+ objectRef, tool)` is a structural AdminShell seam: it registers the required
139
+ `{ type: 'object-form', id: objectRef }` subject and returns the shell's
140
+ disposer without making Fields depend on `smrt-svelte`.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=__smrt-register__.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"__smrt-register__.d.ts","sourceRoot":"","sources":["../src/__smrt-register__.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import { DatabaseInterface } from '@happyvertical/sql';
2
+ import { ExplainedObjectFieldPolicy } from './types.js';
3
+ export declare function getFieldPolicyCacheTtlMs(): number;
4
+ export declare function getCachedFieldPolicy(objectRef: string, tenantId: string | null | undefined, userId: string | null | undefined, db: DatabaseInterface | unknown, hierarchyLoader?: unknown): ExplainedObjectFieldPolicy | null;
5
+ export declare function setCachedFieldPolicy(objectRef: string, tenantId: string | null | undefined, userId: string | null | undefined, db: DatabaseInterface | unknown, value: ExplainedObjectFieldPolicy, hierarchyLoader?: unknown): void;
6
+ /**
7
+ * Drop every cached resolution for `(db, objectRef)`.
8
+ *
9
+ * Deliberately coarser than the prompts precedent (which deletes a single
10
+ * `(key, tenantId)` entry when the tenant is known): tenant HIERARCHY makes a
11
+ * parent-tenant row change affect every descendant tenant's resolution, and a
12
+ * lock or app-row change affects user-tier entries too, so precise
13
+ * invalidation would have to know the whole tenant tree. Per-objectRef prefix
14
+ * invalidation is always correct and the 30s TTL keeps the cost bounded.
15
+ */
16
+ export declare function invalidateFieldPolicyCache(objectRef: string, db: DatabaseInterface | unknown): void;
17
+ export declare function clearFieldPolicyCache(): void;
18
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AA2F7D,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,EAAE,EAAE,iBAAiB,GAAG,OAAO,EAC/B,eAAe,CAAC,EAAE,OAAO,GACxB,0BAA0B,GAAG,IAAI,CAoBnC;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,EAAE,EAAE,iBAAiB,GAAG,OAAO,EAC/B,KAAK,EAAE,0BAA0B,EACjC,eAAe,CAAC,EAAE,OAAO,GACxB,IAAI,CAQN;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,iBAAiB,GAAG,OAAO,GAC9B,IAAI,CAON;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
@@ -0,0 +1,95 @@
1
+ import { SmrtCollection } from '@happyvertical/smrt-core';
2
+ import { FieldPolicy } from '../models/FieldPolicy.js';
3
+ import { FieldPolicyAuditSnapshot, FieldPolicyBatchResult, FieldPolicyEditorStateResult } from '../types.js';
4
+ /** Public cap shared by the server catalog and browser adapter. */
5
+ export declare const MAX_FIELD_POLICY_AUDIT_OBJECT_REFS = 100;
6
+ /** Count queries are projected, so they can cover a page plus an off-page selection. */
7
+ export declare const MAX_FIELD_POLICY_AUDIT_COUNT_REFS: number;
8
+ /**
9
+ * Collection surface for {@link FieldPolicy} rows plus the batch resolve
10
+ * action consumed by client bootstrapping (#2048).
11
+ *
12
+ * `resolveBatch` is a custom collection-scoped action (NOT a system route —
13
+ * core's generated system trio is closed): the generated route parses the
14
+ * body, calls the method on the app-configured collection instance (which
15
+ * carries the app database), and serializes the plain result.
16
+ *
17
+ * Exposure note: a decorated collection's config becomes the RUNTIME registry
18
+ * authority for its item class (core merges the collection registration onto
19
+ * the item slot), while build-time generation reads each manifest object's
20
+ * own config. This config therefore mirrors FieldPolicy's API posture —
21
+ * writes open plus the batch action, reads CLOSED (generated list/get would
22
+ * enumerate every tenant's/user's rows) — and closes the runtime CLI/MCP
23
+ * surfaces entirely (the ContentContributions precedent; the cli↔api
24
+ * coherence gate does not admit standard CRUD entries on a collection's
25
+ * `cli.include`). Keep the api include lists in lockstep with FieldPolicy's.
26
+ */
27
+ export declare class FieldPolicyCollection extends SmrtCollection<FieldPolicy> {
28
+ static readonly _itemClass: typeof FieldPolicy;
29
+ /**
30
+ * Permission-gated, tenant-scoped audit read for the defaults control
31
+ * panel. It returns editable own-tenant rows, read-only app summaries,
32
+ * projected user override counts, and identity-only manifest drift rows.
33
+ */
34
+ policyAudit(options?: {
35
+ objectRefs?: string[];
36
+ countObjectRefs?: string[];
37
+ /** Capability-only bootstrap for catalog builders before page selection. */
38
+ summaryOnly?: boolean;
39
+ /** Return row/count roll-ups without resolving field-policy layers. */
40
+ countsOnly?: boolean;
41
+ /** Return the first bounded page of manifest drift candidates. */
42
+ includeDrift?: boolean;
43
+ }): Promise<FieldPolicyAuditSnapshot>;
44
+ private resolveAuditPolicies;
45
+ /** All app-scope rows for an object, keyed by field name. */
46
+ getAppRows(objectRef: string): Promise<Map<string, FieldPolicy>>;
47
+ /**
48
+ * All tenant-scope rows for an object across a tenant chain, keyed
49
+ * `tenantId → fieldName → row`.
50
+ */
51
+ getTenantRows(objectRef: string, tenantIds: string[]): Promise<Map<string, Map<string, FieldPolicy>>>;
52
+ /** All user-scope rows for an object and user, keyed by field name. */
53
+ getUserRows(objectRef: string, userId: string): Promise<Map<string, FieldPolicy>>;
54
+ /**
55
+ * Resolve merged field policy for a set of objectRefs for the CURRENT
56
+ * caller, gated for public consumption.
57
+ *
58
+ * Caller identity comes exclusively from the ambient tenant context
59
+ * (established by the app's auth hook, e.g. smrt-users' session context) —
60
+ * the request body cannot select another tenant or user (fail closed).
61
+ * Server-side consumers wanting explicit identities call
62
+ * `resolveFieldPolicy()` directly instead.
63
+ *
64
+ * Field gating mirrors the REST serializer's derivation (`sensitive` /
65
+ * `readPermission` read from both the top level and `_meta`): sensitive and
66
+ * read-permission-gated fields are ABSENT from the response for every
67
+ * caller (the generated action route cannot convey per-caller grants to
68
+ * this method, so gated fields fail closed), and transient fields are
69
+ * stripped for parity with generated client field definitions.
70
+ */
71
+ resolveBatch(options?: {
72
+ objectRefs?: string[];
73
+ }): Promise<FieldPolicyBatchResult>;
74
+ /**
75
+ * Context-derived bootstrap data for the policy gear. This is deliberately
76
+ * a collection action instead of reopening list/get: a caller can inspect
77
+ * only their safe effective policy and rows/layers they are permitted to
78
+ * edit, never arbitrary tenant or user policy rows.
79
+ */
80
+ getEditorState(options?: {
81
+ objectRef?: string;
82
+ }): Promise<FieldPolicyEditorStateResult>;
83
+ /**
84
+ * Compute the non-disclosing fallback signal used only by personal drafts.
85
+ * Passing no user id resolves exactly code/app/tenant precedence, including
86
+ * the real tenant hierarchy, while keeping every lower-layer value server
87
+ * side. The public map is limited to fields already admitted by the editor
88
+ * response's security rail.
89
+ */
90
+ private getPersonalLowerDefaultUsability;
91
+ private gateResolvedForPublicResponse;
92
+ private gateExplainedForEditorResponse;
93
+ private toEditorRows;
94
+ }
95
+ //# sourceMappingURL=FieldPolicyCollection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FieldPolicyCollection.d.ts","sourceRoot":"","sources":["../../src/collections/FieldPolicyCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAQ,MAAM,0BAA0B,CAAC;AAiBhE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAKvD,OAAO,KAAK,EAGV,wBAAwB,EACxB,sBAAsB,EAItB,4BAA4B,EAE7B,MAAM,aAAa,CAAC;AAIrB,mEAAmE;AACnE,eAAO,MAAM,kCAAkC,MAAwB,CAAC;AACxE,wFAAwF;AACxF,eAAO,MAAM,iCAAiC,QAA4B,CAAC;AAE3E;;;;;;;;;;;;;;;;;;GAkBG;AAQH,qBAoCa,qBAAsB,SAAQ,cAAc,CAAC,WAAW,CAAC;IACpE,MAAM,CAAC,QAAQ,CAAC,UAAU,qBAAe;IAEzC;;;;OAIG;IACG,WAAW,CACf,OAAO,GAAE;QACP,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,4EAA4E;QAC5E,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,uEAAuE;QACvE,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,kEAAkE;QAClE,YAAY,CAAC,EAAE,OAAO,CAAC;KACnB,GACL,OAAO,CAAC,wBAAwB,CAAC;YA+NtB,oBAAoB;IA6BlC,6DAA6D;IACvD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAWtE;;;OAGG;IACG,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAuBjD,uEAAuE;IACjE,WAAW,CACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAWpC;;;;;;;;;;;;;;;;OAgBG;IACG,YAAY,CAChB,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;KAAO,GACtC,OAAO,CAAC,sBAAsB,CAAC;IAuClC;;;;;OAKG;IACG,cAAc,CAClB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACnC,OAAO,CAAC,4BAA4B,CAAC;IAsGxC;;;;;;OAMG;YACW,gCAAgC;YAuBhC,6BAA6B;YAwB7B,8BAA8B;IAiC5C,OAAO,CAAC,YAAY;CAsBrB"}
@@ -0,0 +1,77 @@
1
+ import { FieldUIHints, ObjectRegistry } from '@happyvertical/smrt-core';
2
+ import { FieldPolicyDelta, FieldPolicyVisibility } from './types.js';
3
+ /**
4
+ * Field map for one object, keyed by field name (includes inherited fields).
5
+ * Derived structurally from the PUBLIC `ObjectRegistry.getAllFields` return
6
+ * type — core does not export its internal `RegisteredField` name.
7
+ */
8
+ export type FieldDefinitionMap = Awaited<ReturnType<typeof ObjectRegistry.getAllFields>>;
9
+ /** One field's registered metadata, as returned by `getAllFields`. */
10
+ export type RegisteredFieldInfo = FieldDefinitionMap extends Map<string, infer F> ? F : never;
11
+ /**
12
+ * Resolve `objectRef` (qualified `@package/name:ClassName`) against the live
13
+ * registry, throwing a descriptive error when the class is unknown.
14
+ */
15
+ export declare function requireRegisteredObject(objectRef: string): void;
16
+ /** Load the full (inherited) field map for a registered objectRef. */
17
+ export declare function getObjectFieldMap(objectRef: string): Promise<FieldDefinitionMap>;
18
+ /**
19
+ * Narrow a manifest `_meta.ui` bag to the known {@link FieldUIHints} keys with
20
+ * their expected primitive types, dropping junk (mirrors the sanitization the
21
+ * web emission applies in core's `web-collections.ts`).
22
+ */
23
+ export declare function sanitizeFieldUIHints(value: unknown): FieldUIHints | undefined;
24
+ /** Security rail: `sensitive` may live top-level or under `_meta` (STI merges). */
25
+ export declare function isSensitiveField(field: RegisteredFieldInfo): boolean;
26
+ /** Security rail: `readPermission` may live top-level or under `_meta`. */
27
+ export declare function getFieldReadPermission(field: RegisteredFieldInfo): string | undefined;
28
+ export declare function isTransientField(field: RegisteredFieldInfo): boolean;
29
+ /**
30
+ * True when a registered field can receive a policy row. Keep this shared by
31
+ * the resolver and the catalog audit: otherwise a row that never resolves can
32
+ * accidentally be presented as an editable setting.
33
+ */
34
+ export declare function isPolicyAddressableField(field: RegisteredFieldInfo): boolean;
35
+ /**
36
+ * A field is required when flagged required and not explicitly nullable.
37
+ *
38
+ * `nullable` is read from BOTH the top level and `_meta` for the same reason
39
+ * `sensitive`/`readPermission`/`transient` are: registrations reach the
40
+ * registry through several paths (decorator, manifest, STI merge) and land the
41
+ * flag in either place. Checking only one side made the pair asymmetric —
42
+ * `required` was read from both while `nullable` was read from one.
43
+ */
44
+ export declare function isRequiredField(field: RegisteredFieldInfo): boolean;
45
+ /** The manifest/code default for a field, boxed; `undefined` when none. */
46
+ export declare function getCodeDefault(field: RegisteredFieldInfo): {
47
+ value: unknown;
48
+ } | undefined;
49
+ /**
50
+ * A resolved default satisfies the required-field invariant only when it is a
51
+ * value a form could actually submit: explicit `null` and the empty string do
52
+ * not count (a required text field "defaulting" to `''` is still unfilled).
53
+ */
54
+ export declare function isUsableRequiredDefault(defaultBox: {
55
+ value: unknown;
56
+ } | undefined): boolean;
57
+ /**
58
+ * Compute the code-seed visibility for every field of an object using the
59
+ * cold-start rule (#2046): with no `ui.basic` markers anywhere on the object,
60
+ * every field is `basic`; once any field is marked `basic: true`, unmarked
61
+ * fields default to `advanced` (and an explicit `basic: false` is always
62
+ * `advanced`).
63
+ */
64
+ export declare function buildCodeSeedVisibility(fields: FieldDefinitionMap): Map<string, FieldPolicyVisibility>;
65
+ /** Code-seed delta for one field (visibility supplied by the cold-start pass). */
66
+ export declare function buildCodeSeedDelta(field: RegisteredFieldInfo, visibility: FieldPolicyVisibility): FieldPolicyDelta;
67
+ /** Code-seed grouping key (`ui.group`) — not overridable by stored rows. */
68
+ export declare function getCodeSeedGroup(field: RegisteredFieldInfo): string | null;
69
+ /**
70
+ * Type-check a parsed default value against the manifest field type.
71
+ *
72
+ * Explicit `null` is allowed only for optional fields (a required field with a
73
+ * null default has no usable default). Unsupported field types reject defaults
74
+ * outright (fail closed).
75
+ */
76
+ export declare function assertDefaultValueMatchesFieldType(objectRef: string, fieldName: string, field: RegisteredFieldInfo, value: unknown): void;
77
+ //# sourceMappingURL=field-definitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-definitions.d.ts","sourceRoot":"","sources":["../src/field-definitions.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE1E;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,CACtC,UAAU,CAAC,OAAO,cAAc,CAAC,YAAY,CAAC,CAC/C,CAAC;AAEF,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAC7B,kBAAkB,SAAS,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAE9D;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAa/D;AAED,sEAAsE;AACtE,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAG7B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAc7E;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAEpE;AAED,2EAA2E;AAC3E,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,mBAAmB,GACzB,MAAM,GAAG,SAAS,CAMpB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAO5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAKnE;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAC5B,KAAK,EAAE,mBAAmB,GACzB;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CAQhC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,GACzC,OAAO,CAKT;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,kBAAkB,GACzB,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAuBpC;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,mBAAmB,EAC1B,UAAU,EAAE,qBAAqB,GAChC,gBAAgB,CAiBlB;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,CAE1E;AAUD;;;;;;GAMG;AACH,wBAAgB,kCAAkC,CAChD,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,OAAO,GACb,IAAI,CAsEN"}
@@ -0,0 +1,46 @@
1
+ import { ExplainedObjectFieldPolicy, ResolvedObjectFieldPolicy, ResolveFieldPolicyOptions } from './types.js';
2
+ /**
3
+ * Resolve the merged field policy for `objectRef` in the given
4
+ * `(tenantId, userId)` context: code seed → app rows → tenant rows (hierarchy
5
+ * walk root → leaf) → user rows. Defaults AND visibility both resolve through
6
+ * the user tier.
7
+ *
8
+ * Results are cached per `(database, objectRef, tenantId, userId)` with a
9
+ * short TTL; `FieldPolicy.save()`/`.delete()` invalidate the object's entries.
10
+ */
11
+ export declare function resolveFieldPolicy(objectRef: string, options?: ResolveFieldPolicyOptions): Promise<ResolvedObjectFieldPolicy>;
12
+ /**
13
+ * The tenant ids whose rows participate in precedence for a tenant, root to
14
+ * leaf. Catalog code uses this instead of reimplementing inheritance-break
15
+ * handling when it decides whether an inherited override is customized.
16
+ */
17
+ export declare function resolveSurvivingTenantChainIds(tenantId: string, options?: ResolveFieldPolicyOptions): Promise<string[]>;
18
+ /**
19
+ * Explain variant: the merged result plus ordered per-layer contributions for
20
+ * each field, so the gear UI (#2049, "shows inherited base") and the control
21
+ * panel (#2050, effective-value-per-layer) never re-derive precedence.
22
+ *
23
+ * A user-layer row suppressed by an effective org lock is omitted from the
24
+ * layer list too — the listed layers always reproduce the merged result.
25
+ */
26
+ export declare function resolveFieldPolicyExplained(objectRef: string, options?: ResolveFieldPolicyOptions): Promise<ExplainedObjectFieldPolicy>;
27
+ /**
28
+ * Whether an import failure means `@happyvertical/smrt-users` is simply not
29
+ * installed (→ flat-tenant fallback) rather than installed-but-broken
30
+ * (→ rethrow, surfacing the problem instead of silently losing ancestor
31
+ * locks/defaults).
32
+ *
33
+ * The decision is made on the missing-module TARGET parsed from Node's
34
+ * `Cannot find package/module '<specifier>'` message (walking the full
35
+ * `cause` chain): only a target that IS smrt-users (or one of its subpaths)
36
+ * counts. A transitive failure INSIDE an installed smrt-users names the
37
+ * other package as the target — with the users path merely appearing as the
38
+ * importer — and therefore rethrows. `importWorkspaceModule`'s own
39
+ * source-fallback wrapper ("Failed to load @happyvertical/smrt-users for
40
+ * ...") is also accepted: it is thrown only when the users package itself
41
+ * cannot be located.
42
+ *
43
+ * Exported for direct testing; not re-exported from the package index.
44
+ */
45
+ export declare function isMissingUsersDependency(error: unknown): boolean;
46
+ //# sourceMappingURL=field-policy-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-policy-resolver.d.ts","sourceRoot":"","sources":["../src/field-policy-resolver.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACV,0BAA0B,EAQ1B,yBAAyB,EACzB,yBAAyB,EAE1B,MAAM,YAAY,CAAC;AAYpB;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,yBAAyB,CAAC,CAGpC;AAED;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,MAAM,EAAE,CAAC,CAInB;AAED;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,0BAA0B,CAAC,CA0JrC;AA0MD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAsBhE"}