@svadmin/supabase 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svadmin/supabase",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "Supabase adapters — DataProvider, AuthProvider, LiveProvider, AuditHandler",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -16,8 +16,10 @@
16
16
  }
17
17
  },
18
18
  "peerDependencies": {
19
- "@svadmin/core": "^0.21.0",
20
- "@supabase/supabase-js": "^2.0.0"
19
+ "@svadmin/core": "^0.21.2",
20
+ "@supabase/supabase-js": "^2.0.0",
21
+ "@refinedev/supabase": "^5.0.0",
22
+ "@svadmin/refine-adapter": "^0.9.3"
21
23
  },
22
24
  "license": "MIT",
23
25
  "author": "zuohuadong",
@@ -1,113 +1,16 @@
1
- // Supabase DataProvider
2
- import type { SupabaseClient } from '@supabase/supabase-js';
3
- import type {
4
- DataProvider, GetListParams, GetListResult, GetOneParams, GetOneResult,
5
- CreateParams, CreateResult, UpdateParams, UpdateResult, DeleteParams, DeleteResult,
6
- GetManyParams, GetManyResult, CreateManyParams, CreateManyResult,
7
- UpdateManyParams, UpdateManyResult, DeleteManyParams, DeleteManyResult,
8
- CustomParams, CustomResult, BaseRecord,
9
- } from '@svadmin/core';
10
-
11
- export function createSupabaseDataProvider(client: SupabaseClient, apiUrl?: string): DataProvider {
12
- const resolvedApiUrl = apiUrl ?? '';
13
-
14
- return {
15
- getApiUrl: () => resolvedApiUrl,
16
-
17
- async getList<TData extends BaseRecord = BaseRecord>({ resource, pagination, sorters, filters, meta }: GetListParams): Promise<GetListResult<TData>> {
18
- const { current = 1, pageSize = 10 } = pagination ?? {};
19
- const from = (current - 1) * pageSize;
20
- const to = from + pageSize - 1;
21
- const select = (meta?.select as string) ?? '*';
22
-
23
- let query = client.from(resource).select(select, { count: 'exact' }).range(from, to);
24
-
25
- if (sorters?.length) {
26
- for (const sort of sorters) {
27
- query = query.order(sort.field, { ascending: sort.order === 'asc' });
28
- }
29
- }
30
-
31
- if (filters?.length) {
32
- for (const filter of filters) {
33
- switch (filter.operator) {
34
- case 'eq': query = query.eq(filter.field, filter.value); break;
35
- case 'ne': query = query.neq(filter.field, filter.value); break;
36
- case 'lt': query = query.lt(filter.field, filter.value); break;
37
- case 'gt': query = query.gt(filter.field, filter.value); break;
38
- case 'lte': query = query.lte(filter.field, filter.value); break;
39
- case 'gte': query = query.gte(filter.field, filter.value); break;
40
- case 'contains': query = query.ilike(filter.field, `%${filter.value}%`); break;
41
- case 'in': query = query.in(filter.field, filter.value as unknown[]); break;
42
- case 'null': query = query.is(filter.field, null); break;
43
- }
44
- }
45
- }
46
-
47
- const { data, count, error } = await query;
48
- if (error) throw error;
49
- return { data: (data ?? []) as unknown as TData[], total: count ?? 0 };
50
- },
51
-
52
- async getOne<TData extends BaseRecord = BaseRecord>({ resource, id, meta }: GetOneParams): Promise<GetOneResult<TData>> {
53
- const select = (meta?.select as string) ?? '*';
54
- const { data, error } = await client.from(resource).select(select).eq('id', id).single();
55
- if (error) throw error;
56
- return { data: data as unknown as TData };
57
- },
58
-
59
- async create<TData extends BaseRecord = BaseRecord, TVariables = unknown>({ resource, variables }: CreateParams<TVariables>): Promise<CreateResult<TData>> {
60
- const { data, error } = await client.from(resource).insert(variables).select().single();
61
- if (error) throw error;
62
- return { data: data as TData };
63
- },
64
-
65
- async update<TData extends BaseRecord = BaseRecord, TVariables = unknown>({ resource, id, variables }: UpdateParams<TVariables>): Promise<UpdateResult<TData>> {
66
- const { data, error } = await client.from(resource).update(variables).eq('id', id).select().single();
67
- if (error) throw error;
68
- return { data: data as TData };
69
- },
70
-
71
- async deleteOne<TData extends BaseRecord = BaseRecord, TVariables = unknown>({ resource, id }: DeleteParams<TVariables>): Promise<DeleteResult<TData>> {
72
- const { data, error } = await client.from(resource).delete().eq('id', id).select().single();
73
- if (error) throw error;
74
- return { data: data as TData };
75
- },
76
-
77
- async getMany<TData extends BaseRecord = BaseRecord>({ resource, ids, meta }: GetManyParams): Promise<GetManyResult<TData>> {
78
- const select = (meta?.select as string) ?? '*';
79
- const { data, error } = await client.from(resource).select(select).in('id', ids);
80
- if (error) throw error;
81
- return { data: (data ?? []) as unknown as TData[] };
82
- },
83
-
84
- async createMany<TData extends BaseRecord = BaseRecord, TVariables = unknown>({ resource, variables }: CreateManyParams<TVariables>): Promise<CreateManyResult<TData>> {
85
- const { data, error } = await client.from(resource).insert(variables).select();
86
- if (error) throw error;
87
- return { data: (data ?? []) as TData[] };
88
- },
89
-
90
- async updateMany<TData extends BaseRecord = BaseRecord, TVariables = unknown>({ resource, ids, variables }: UpdateManyParams<TVariables>): Promise<UpdateManyResult<TData>> {
91
- const { data, error } = await client.from(resource).update(variables).in('id', ids).select();
92
- if (error) throw error;
93
- return { data: (data ?? []) as TData[] };
94
- },
95
-
96
- async deleteMany<TData extends BaseRecord = BaseRecord, TVariables = unknown>({ resource, ids }: DeleteManyParams<TVariables>): Promise<DeleteManyResult<TData>> {
97
- const { data, error } = await client.from(resource).delete().in('id', ids).select();
98
- if (error) throw error;
99
- return { data: (data ?? []) as TData[] };
100
- },
101
-
102
- async custom<TData = unknown, TVariables = unknown>({ url, method, payload, headers }: CustomParams<TVariables>): Promise<CustomResult<TData>> {
103
- const response = await fetch(url, {
104
- method: method.toUpperCase(),
105
- headers: { 'Content-Type': 'application/json', ...headers },
106
- body: payload ? JSON.stringify(payload) : undefined,
107
- });
108
- if (!response.ok) throw new Error(`Custom request failed: ${response.status}`);
109
- const data = await response.json();
110
- return { data: data as TData };
111
- },
112
- };
1
+ import type { DataProvider } from '@svadmin/core';
2
+ import { createRefineAdapter } from '@svadmin/refine-adapter';
3
+ /**
4
+ * Creates a supabase data provider using the official @refinedev/supabase package.
5
+ * Requires `@refinedev/supabase` to be installed.
6
+ *
7
+ * @param args Arguments required by @refinedev/supabase
8
+ * @returns A fully compatible svadmin DataProvider
9
+ */
10
+ export async function createSupabaseDataProvider(...args: any[]): Promise<DataProvider> {
11
+ // @ts-ignore Peer dependency
12
+ const pkg = (await import('@refinedev/supabase')) as any;
13
+ const init: any = pkg.dataProvider || pkg.default || pkg.DataProvider;
14
+ const refineProvider = init(...args);
15
+ return createRefineAdapter(refineProvider);
113
16
  }
@@ -3,43 +3,56 @@ import type { SupabaseClient, RealtimeChannel } from '@supabase/supabase-js';
3
3
  import type { LiveProvider, LiveEvent } from '@svadmin/core';
4
4
 
5
5
  export function createSupabaseLiveProvider(client: SupabaseClient): LiveProvider {
6
+ const subscribers = new Map<string, Set<(event: LiveEvent) => void>>();
6
7
  const channels = new Map<string, RealtimeChannel>();
7
8
 
8
9
  function getOrCreateChannel(resource: string): RealtimeChannel {
9
10
  let channel = channels.get(resource);
10
11
  if (!channel) {
11
- channel = client.channel(`live-${resource}`);
12
- channels.set(resource, channel);
13
- }
14
- return channel;
15
- }
16
-
17
- return {
18
- subscribe({ resource, callback }) {
19
- const channel = getOrCreateChannel(resource)
12
+ channel = client.channel(`live-${resource}`)
20
13
  .on(
21
14
  'postgres_changes',
22
15
  { event: '*', schema: 'public', table: resource },
23
16
  (payload) => {
24
- callback({
17
+ const event: LiveEvent = {
25
18
  type: payload.eventType as LiveEvent['type'],
26
19
  resource,
27
20
  payload: (payload.new ?? payload.old ?? {}) as Record<string, unknown>,
28
- });
21
+ };
22
+ subscribers.get(resource)?.forEach(cb => cb(event));
29
23
  }
30
24
  )
31
- .on('broadcast', { event: 'live-event' }, ({ payload: broadcastPayload }) => {
32
- if (broadcastPayload) {
33
- callback(broadcastPayload as LiveEvent);
25
+ .on('broadcast', { event: 'live-event' }, ({ payload }) => {
26
+ if (payload) {
27
+ subscribers.get(resource)?.forEach(cb => cb(payload as LiveEvent));
34
28
  }
35
29
  })
36
30
  .subscribe();
37
-
38
31
  channels.set(resource, channel);
32
+ }
33
+ return channel;
34
+ }
35
+
36
+ return {
37
+ subscribe({ resource, callback }) {
38
+ if (!subscribers.has(resource)) subscribers.set(resource, new Set());
39
+ subscribers.get(resource)!.add(callback);
40
+
41
+ getOrCreateChannel(resource);
39
42
 
40
43
  return () => {
41
- channel.unsubscribe();
42
- channels.delete(resource);
44
+ const cbs = subscribers.get(resource);
45
+ if (cbs) {
46
+ cbs.delete(callback);
47
+ if (cbs.size === 0) {
48
+ subscribers.delete(resource);
49
+ const channel = channels.get(resource);
50
+ if (channel) {
51
+ channel.unsubscribe();
52
+ channels.delete(resource);
53
+ }
54
+ }
55
+ }
43
56
  };
44
57
  },
45
58