@svadmin/core 0.50.0 → 0.52.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.
Files changed (97) hide show
  1. package/package.json +21 -4
  2. package/src/access-control-contract.ts +250 -0
  3. package/src/adapters/casbin.ts +20 -14
  4. package/src/adapters/casl.ts +22 -19
  5. package/src/admin-tool.ts +7 -7
  6. package/src/audit-contract.ts +105 -0
  7. package/src/audit.ts +88 -128
  8. package/src/auth-hooks.svelte.ts +593 -261
  9. package/src/auth-mutation-contract.ts +143 -0
  10. package/src/auth-query-contract.ts +97 -0
  11. package/src/captured-mutation.svelte.ts +45 -0
  12. package/src/chatProvider.svelte.ts +1 -1
  13. package/src/command-contract.ts +195 -0
  14. package/src/context.svelte.ts +217 -205
  15. package/src/contract-context.svelte.ts +37 -0
  16. package/src/contract-form.svelte.ts +566 -0
  17. package/src/create-contract.ts +56 -0
  18. package/src/create-hooks.svelte.ts +347 -0
  19. package/src/create-many-contract.ts +90 -0
  20. package/src/create-many-hooks.svelte.ts +396 -0
  21. package/src/data-transfer.svelte.ts +1 -215
  22. package/src/defined-options.ts +50 -0
  23. package/src/delete-contract.ts +50 -0
  24. package/src/delete-hooks.svelte.ts +403 -0
  25. package/src/delete-many-contract.ts +60 -0
  26. package/src/delete-many-hooks.svelte.ts +402 -0
  27. package/src/enterprise.ts +4 -4
  28. package/src/export-format.ts +16 -14
  29. package/src/export-hooks.svelte.ts +191 -0
  30. package/src/feature-gate-contract.ts +53 -0
  31. package/src/hook-utils.svelte.ts +53 -105
  32. package/src/hooks.svelte.ts +19 -776
  33. package/src/http.ts +88 -87
  34. package/src/i18n.svelte.ts +56 -2
  35. package/src/import-contract.ts +106 -0
  36. package/src/import-hooks.svelte.ts +310 -0
  37. package/src/index.ts +77 -30
  38. package/src/inferencer-graphql.ts +7 -6
  39. package/src/infinite-query.svelte.ts +228 -0
  40. package/src/invalidation-contract.ts +26 -0
  41. package/src/live-sse.ts +91 -127
  42. package/src/live-subscription.svelte.ts +130 -0
  43. package/src/live-transport.ts +127 -0
  44. package/src/live-websocket.ts +85 -118
  45. package/src/live.svelte.ts +66 -68
  46. package/src/notification.svelte.ts +17 -15
  47. package/src/permission-catalog.ts +121 -0
  48. package/src/permission-hints-contract.ts +48 -0
  49. package/src/permissions.svelte.ts +112 -59
  50. package/src/plain-data.ts +61 -0
  51. package/src/provider-bundle.ts +85 -79
  52. package/src/provider-response.ts +35 -0
  53. package/src/query-hooks.svelte.ts +241 -288
  54. package/src/query-invalidation.ts +172 -0
  55. package/src/query-keys.ts +221 -110
  56. package/src/query-session.svelte.ts +216 -0
  57. package/src/query-snapshot.ts +144 -0
  58. package/src/reactive-projection.ts +53 -0
  59. package/src/record-decoder.ts +63 -0
  60. package/src/resource-binding.svelte.ts +19 -0
  61. package/src/resource-contract.ts +595 -0
  62. package/src/resource-mutation-types.ts +30 -0
  63. package/src/resource-schemas.ts +371 -0
  64. package/src/resource-transport-config.ts +156 -0
  65. package/src/route-parsing.ts +11 -11
  66. package/src/router-provider.ts +64 -59
  67. package/src/router.ts +8 -3
  68. package/src/routing-hooks.svelte.ts +90 -62
  69. package/src/schema-validation.ts +92 -0
  70. package/src/schema.ts +13 -0
  71. package/src/select-options.ts +95 -0
  72. package/src/select-query.svelte.ts +191 -0
  73. package/src/session-query.svelte.ts +88 -0
  74. package/src/strict-command-hooks.svelte.ts +333 -0
  75. package/src/strict-hooks.svelte.ts +198 -0
  76. package/src/table-hooks.svelte.ts +180 -174
  77. package/src/table-state.svelte.ts +117 -117
  78. package/src/task-contract.ts +87 -0
  79. package/src/task-hooks.svelte.ts +193 -149
  80. package/src/task-provider.ts +115 -0
  81. package/src/task-subscription.ts +132 -0
  82. package/src/theme.svelte.ts +155 -154
  83. package/src/toast.svelte.ts +38 -37
  84. package/src/types.ts +55 -108
  85. package/src/unsafe.ts +7 -0
  86. package/src/update-contract.ts +65 -0
  87. package/src/update-hooks.svelte.ts +347 -0
  88. package/src/update-many-contract.ts +79 -0
  89. package/src/update-many-hooks.svelte.ts +373 -0
  90. package/src/url-sync.ts +11 -10
  91. package/src/useCan.ts +96 -31
  92. package/src/useParsed.svelte.ts +18 -14
  93. package/src/useStepsForm.svelte.ts +123 -63
  94. package/src/utility-hooks.svelte.ts +101 -158
  95. package/src/form-hooks.svelte.ts +0 -889
  96. package/src/mutation-hooks.svelte.ts +0 -561
  97. package/src/schema-form.ts +0 -31
@@ -0,0 +1,198 @@
1
+ import { definedOptions } from './defined-options';
2
+ import * as query from './query-hooks.svelte';
3
+ import * as bulk from './hooks.svelte';
4
+ import { createTableQuery,type UseTableOptions } from './table-hooks.svelte';
5
+ import type { ContractOptions } from './contract-context.svelte';
6
+ import { captureAdminContext } from './context.svelte';
7
+ import { contractKey,validateContractId,parseContractId,parseContractRecord,type ResourceContract,type ContractSchemas,type ContractRecord,type ContractId,type ContractFormAction } from './resource-contract';
8
+ import type { RecordDecoder } from './record-decoder';
9
+ import type { KnownResources,Filter } from './types';
10
+ import { useQueryClient } from '@tanstack/svelte-query';
11
+ import { replaceReactiveMembers } from './reactive-projection';
12
+ import { snapshotInvalidationParams } from './invalidation-contract';
13
+ import { captureQueryProvider } from './query-snapshot';
14
+ import { captureAuthLiveScope } from './auth-hooks.svelte';
15
+ import { invalidateOwnedQueries, refreshSuperseded, type RefreshScope } from './query-invalidation';
16
+ import { useContractDelete, type ContractDeleteOptions } from './delete-hooks.svelte';
17
+ import { useContractUpdate, type ContractUpdateOptions } from './update-hooks.svelte';
18
+ import { useContractForm, type ContractFormOptions } from './contract-form.svelte';
19
+ import { useContractDeleteMany, type ContractDeleteManyOptions } from './delete-many-hooks.svelte';
20
+ import { useContractUpdateMany, type ContractUpdateManyOptions } from './update-many-hooks.svelte';
21
+ import type { ContractUpdateManyParams } from './update-many-contract';
22
+ import type { ContractDeleteManyParams } from './delete-many-contract';
23
+ import { useContractCreateMany, type ContractCreateManyOptions } from './create-many-hooks.svelte';
24
+ import { useContractCreate, type ContractCreateOptions } from './create-hooks.svelte';
25
+
26
+ type Field<T>=Extract<keyof T,string>;
27
+ type ValueField<T>={ [K in Field<T>]-?: T[K] extends string|number? K:never }[Field<T>];
28
+ type FieldPredicate<T>=
29
+ |{ operator: 'eq'|'ne'; value: Exclude<T,undefined> }
30
+ |{ operator: 'in'|'nin'; value: Exclude<T,undefined>[] }
31
+ |{ operator: 'null'|'nnull'; value: null }
32
+ |(NonNullable<T> extends string? { operator: 'contains'|'ncontains'|'startswith'|'endswith'; value: NonNullable<T> }:never)
33
+ |(NonNullable<T> extends string|number? (
34
+ |{ operator: 'lt'|'lte'|'gt'|'gte'; value: NonNullable<T> }
35
+ |{ operator: 'between'|'nbetween'; value: [NonNullable<T>,NonNullable<T>] }
36
+ ):never);
37
+ export type ContractFilter<T>=string extends keyof T ? Filter : Filter&(
38
+ |{ [K in Field<T>]: { field: K }&FieldPredicate<T[K]> }[Field<T>]
39
+ |{ operator: 'and'|'or'; value: ContractFilter<T>[] });
40
+ export type ContractSort<T>={ field: Field<T>; order: 'asc'|'desc' };
41
+ type Bound<S extends ContractSchemas>={ resource: ResourceContract<S> };
42
+ type QueryOptions<O,S extends ContractSchemas>=
43
+ Omit<O,'resource'|'contract'|'id'|'ids'|'filters'|'sorters'>&Bound<S>;
44
+ type ListOptions<O,S extends ContractSchemas>=QueryOptions<O,S>&{
45
+ filters?: ContractFilter<NoInfer<ContractRecord<S>>>[];
46
+ sorters?: ContractSort<NoInfer<ContractRecord<S>>>[];
47
+ };
48
+ type Id<S extends ContractSchemas>=NoInfer<ContractId<S>>;
49
+ type Row<S extends ContractSchemas>=ContractRecord<S>;
50
+
51
+ function bind<O extends Bound<ContractSchemas>>(options: O): Omit<O,'resource'|'contract'>&{ resource: KnownResources }&ContractOptions {
52
+ contractKey(options.resource);
53
+ return replaceReactiveMembers(options,{
54
+ get resource() {
55
+ contractKey(options.resource);
56
+ return options.resource.name;
57
+ },
58
+ get contract() {
59
+ contractKey(options.resource);
60
+ return options.resource;
61
+ },
62
+ });
63
+ }
64
+ function getter<O extends Bound<ContractSchemas>>(options: query.MaybeGetter<O>) {
65
+ return () => bind(typeof options==='function'? options():options);
66
+ }
67
+
68
+ function recordDecoder<S extends ContractSchemas>(options: query.MaybeGetter<Bound<S>>): () => RecordDecoder<Row<S>> {
69
+ return () => {
70
+ const contract=(typeof options==='function'? options():options).resource;
71
+ return value => parseContractRecord(contract,value);
72
+ };
73
+ }
74
+
75
+ export function useList<S extends ContractSchemas>(options: query.MaybeGetter<ListOptions<query.UseListOptions,S>>) {
76
+ return query.createListQuery(getter(options),recordDecoder(options));
77
+ }
78
+ export function useOne<S extends ContractSchemas>(options: query.MaybeGetter<QueryOptions<query.UseOneOptions,S>&{ id: Id<S> }>) {
79
+ return query.createOneQuery(getter(options),recordDecoder(options));
80
+ }
81
+ export function useMany<S extends ContractSchemas>(options: query.MaybeGetter<QueryOptions<query.UseManyOptions,S>&{ ids: Id<S>[] }>) {
82
+ return query.createManyQuery(getter(options),recordDecoder(options));
83
+ }
84
+ export function useShow<S extends ContractSchemas>(options: query.MaybeGetter<QueryOptions<query.UseOneOptions,S>&{ id: Id<S> }>) {
85
+ const result=query.createShowQuery(getter(options),recordDecoder(options));
86
+ return replaceReactiveMembers(result,{
87
+ get showId(): Id<S> {
88
+ return parseContractId((typeof options==='function'? options():options).resource,result.showId);
89
+ },
90
+ setShowId(id: Id<S>) {
91
+ validateContractId((typeof options==='function'? options():options).resource,id);
92
+ result.setShowId(id);
93
+ },
94
+ });
95
+ }
96
+ export function useInfiniteList<S extends ContractSchemas>(options: ListOptions<bulk.UseInfiniteListOptions,S>) {
97
+ return bulk.createInfiniteListQuery(bind(options),recordDecoder(options));
98
+ }
99
+ export function useSelect<S extends ContractSchemas>(
100
+ options: ListOptions<Omit<bulk.UseSelectOptions<Row<S>>,'optionLabel'|'optionValue'|'defaultValue'|'onSearch'>,S>&{
101
+ optionLabel: Field<NoInfer<Row<S>>>|((row: NoInfer<Row<S>>) => string);
102
+ optionValue: ValueField<NoInfer<Row<S>>>|((row: NoInfer<Row<S>>) => string|number);
103
+ defaultValue?: Id<S>[];
104
+ onSearch?: (value: string) => ContractFilter<NoInfer<Row<S>>>[];
105
+ },
106
+ ) {
107
+ return bulk.createSelectQuery(bind(options),recordDecoder(options));
108
+ }
109
+ export function useTable<S extends ContractSchemas>(
110
+ options: query.MaybeGetter<QueryOptions<UseTableOptions,S>&{
111
+ sorters?: { initial?: ContractSort<NoInfer<Row<S>>>[]; permanent?: ContractSort<NoInfer<Row<S>>>[]; mode?: 'off'|'server' };
112
+ filters?: { initial?: ContractFilter<NoInfer<Row<S>>>[]; permanent?: ContractFilter<NoInfer<Row<S>>>[]; mode?: 'off'|'server'; defaultBehavior?: 'merge'|'replace' };
113
+ }>,
114
+ ) {
115
+ const result=createTableQuery(getter(options),recordDecoder(options));
116
+ return replaceReactiveMembers(result,{
117
+ setSorters(value: ContractSort<Row<S>>[]) { result.setSorters(value); },
118
+ setFilters(value: ContractFilter<Row<S>>[],mode?: 'merge'|'replace') { result.setFilters(value,mode); },
119
+ });
120
+ }
121
+
122
+ export function useCreate<S extends ContractSchemas>(options: ContractCreateOptions<S>) {
123
+ return useContractCreate(options);
124
+ }
125
+ export function useUpdate<S extends ContractSchemas>(options: ContractUpdateOptions<S>) {
126
+ return useContractUpdate(options);
127
+ }
128
+ export function useDelete<S extends ContractSchemas>(options: ContractDeleteOptions<S>) {
129
+ return useContractDelete(options);
130
+ }
131
+ export function useCreateMany<S extends ContractSchemas>(options: ContractCreateManyOptions<S>) {
132
+ return useContractCreateMany(options);
133
+ }
134
+ export function useUpdateMany<S extends ContractSchemas>(options: ContractUpdateManyOptions<S>) {
135
+ return useContractUpdateMany(options);
136
+ }
137
+ export function useDeleteMany<S extends ContractSchemas>(options: ContractDeleteManyOptions<S>) {
138
+ return useContractDeleteMany(options);
139
+ }
140
+
141
+ export function useInvalidate<S extends ContractSchemas>(options: Bound<S>&{ dataProviderName?: string }) {
142
+ contractKey(options.resource);
143
+ const context=captureAdminContext();
144
+ const client=useQueryClient();
145
+ let disposed=false;
146
+ $effect(() => () => { disposed=true; });
147
+ return async (params: { id?: Id<S>; invalidates?: ('list'|'many'|'detail'|'resourceAll')[]|'all'|false }={}): Promise<void> => {
148
+ const input=snapshotInvalidationParams(params);
149
+ const contract=options.resource;
150
+ const key=contractKey(contract);
151
+ if(input.id!==undefined) validateContractId(contract,input.id);
152
+ if(input.invalidates===false||(Array.isArray(input.invalidates)&&input.invalidates.length===0)) return;
153
+ const auth=context.authProvider;
154
+ const authScope=captureAuthLiveScope(auth);
155
+ if(disposed || !authScope.isCurrent()) throw refreshSuperseded();
156
+ const resource=contract.name;
157
+ const providerName=options.dataProviderName;
158
+ // Validate the selected route before context's legacy provider fallback can run.
159
+ const captured=captureQueryProvider(context,{
160
+ resource,contract,...definedOptions({ dataProviderName: providerName }),
161
+ });
162
+ const matcher={ ...context.queryKeyMatcher(resource,providerName),contract: key };
163
+ const tenant=context.tenantCacheKey?.__svadminTenant;
164
+ const current=() => {
165
+ try {
166
+ return !disposed && auth===context.authProvider && authScope.isCurrent() &&
167
+ tenant===context.tenantCacheKey?.__svadminTenant && key===contractKey(options.resource) &&
168
+ matcher.provider===context.queryKeyMatcher(resource,providerName).provider &&
169
+ providerName===options.dataProviderName && captured.source===captureQueryProvider(context,{
170
+ resource,contract: options.resource,...definedOptions({ dataProviderName: providerName }),
171
+ }).source;
172
+ } catch { return false; }
173
+ };
174
+ const scopes: readonly RefreshScope[]=input.invalidates===undefined || input.invalidates==='all'
175
+ ? ['resourceAll'] : input.invalidates;
176
+ await invalidateOwnedQueries({
177
+ client, matcher: { ...matcher,resource }, owner: { source: captured.source,authSession: authScope.cacheKey },
178
+ scopes, current, ...definedOptions({ id: input.id }),
179
+ });
180
+ };
181
+ }
182
+
183
+ export function useForm<S extends ContractSchemas,A extends ContractFormAction>(options: ContractFormOptions<S,A>) {
184
+ return useContractForm(options);
185
+ }
186
+
187
+ export type StrictUseListOptions<S extends ContractSchemas>=ListOptions<query.UseListOptions,S>;
188
+ export type StrictUseOneOptions<S extends ContractSchemas>=QueryOptions<query.UseOneOptions,S>&{ id: Id<S> };
189
+ export type StrictUseManyOptions<S extends ContractSchemas>=QueryOptions<query.UseManyOptions,S>&{ ids: Id<S>[] };
190
+ export type StrictUseInfiniteListOptions<S extends ContractSchemas>=Parameters<typeof useInfiniteList<S>>[0];
191
+ export type StrictUseSelectOptions<S extends ContractSchemas>=Parameters<typeof useSelect<S>>[0];
192
+ export type StrictUseDeleteManyOptions<S extends ContractSchemas>=ContractDeleteManyOptions<S>;
193
+ export type StrictUseDeleteManyMutateParams<S extends ContractSchemas>=ContractDeleteManyParams<S>;
194
+ export type StrictUseUpdateManyMutateParams<S extends ContractSchemas>=ContractUpdateManyParams<S>;
195
+ export type StrictUseCreateManyMutateParams<S extends ContractSchemas>=
196
+ Parameters<ReturnType<typeof useCreateMany<S>>['mutation']['mutateAsync']>[0];
197
+ export type StrictUseFormOptions<S extends ContractSchemas,A extends ContractFormAction>=Parameters<typeof useForm<S,A>>[0];
198
+ export type StrictUseFormReturn<S extends ContractSchemas,A extends ContractFormAction>=ReturnType<typeof useForm<S,A>>;