@ankhorage/supabase-db 1.0.1 → 1.0.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/CHANGELOG.md +12 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +69 -63
- package/dist/adapter.js.map +1 -1
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +34 -55
- package/dist/realtime.js.map +1 -1
- package/package.json +10 -12
- package/src/adapter.test.ts +108 -110
- package/src/adapter.ts +87 -109
- package/src/admin.test.ts +87 -91
- package/src/realtime.test.ts +102 -106
- package/src/realtime.ts +57 -74
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @ankhorage/supabase-db
|
|
2
2
|
|
|
3
|
+
## 1.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5c0d97e: Update Ankhorage dependencies: `@ankhorage/contracts`.
|
|
8
|
+
|
|
9
|
+
## 1.0.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- fb8cbd4: Update Ankhorage dependencies: `@ankhorage/contracts`.
|
|
14
|
+
|
|
3
15
|
## 1.0.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAkB9E,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAkB9E,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAW5F"}
|
package/dist/adapter.js
CHANGED
|
@@ -4,73 +4,70 @@ import { createRealtimeApi } from './realtime.js';
|
|
|
4
4
|
import { validateFilters, validateKey, validateUrl } from './validation.js';
|
|
5
5
|
export function createSupabaseDbAdapter(options) {
|
|
6
6
|
const config = normalizeConfig(options);
|
|
7
|
-
const baseAdapter =
|
|
7
|
+
const baseAdapter = createBaseAdapter(config);
|
|
8
|
+
if (!config.realtime || config.realtimeClient === undefined)
|
|
9
|
+
return baseAdapter;
|
|
10
|
+
return {
|
|
11
|
+
...baseAdapter,
|
|
12
|
+
realtime: createRealtimeApi({
|
|
13
|
+
client: config.realtimeClient,
|
|
14
|
+
defaultSchema: config.schema,
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function createBaseAdapter(config) {
|
|
19
|
+
return {
|
|
8
20
|
capabilities: {
|
|
9
21
|
transactions: false,
|
|
10
22
|
returning: true,
|
|
11
23
|
realtime: config.realtime && config.realtimeClient !== undefined,
|
|
12
24
|
},
|
|
13
|
-
|
|
14
|
-
return
|
|
15
|
-
method: 'GET',
|
|
16
|
-
});
|
|
25
|
+
select(input) {
|
|
26
|
+
return selectRows(config, input);
|
|
17
27
|
},
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
table: input.table,
|
|
21
|
-
columns: input.columns,
|
|
22
|
-
filters: [{ field: input.idField ?? 'id', operator: 'eq', value: input.id }],
|
|
23
|
-
page: { limit: 1 },
|
|
24
|
-
schema: input.schema,
|
|
25
|
-
}), { method: 'GET' });
|
|
26
|
-
if (!result.ok) {
|
|
27
|
-
return result;
|
|
28
|
-
}
|
|
29
|
-
const success = {
|
|
30
|
-
ok: true,
|
|
31
|
-
data: result.data[0] ?? null,
|
|
32
|
-
};
|
|
33
|
-
return success;
|
|
28
|
+
findById(input) {
|
|
29
|
+
return findRowById(config, input);
|
|
34
30
|
},
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return requestRows(config, url, {
|
|
38
|
-
method: 'POST',
|
|
39
|
-
body: JSON.stringify(input.values),
|
|
40
|
-
});
|
|
31
|
+
insert(input) {
|
|
32
|
+
return insertRows(config, input);
|
|
41
33
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (validationError !== null) {
|
|
45
|
-
return validationError;
|
|
46
|
-
}
|
|
47
|
-
const url = buildMutationUrl(config.url, input.table, input.filters);
|
|
48
|
-
return requestRows(config, url, {
|
|
49
|
-
method: 'PATCH',
|
|
50
|
-
body: JSON.stringify(input.values),
|
|
51
|
-
});
|
|
34
|
+
update(input) {
|
|
35
|
+
return updateRows(config, input);
|
|
52
36
|
},
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (validationError !== null) {
|
|
56
|
-
return validationError;
|
|
57
|
-
}
|
|
58
|
-
const url = buildMutationUrl(config.url, input.table, input.filters);
|
|
59
|
-
return requestRows(config, url, {
|
|
60
|
-
method: 'DELETE',
|
|
61
|
-
});
|
|
37
|
+
delete(input) {
|
|
38
|
+
return deleteRows(config, input);
|
|
62
39
|
},
|
|
63
40
|
};
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
41
|
+
}
|
|
42
|
+
function deleteRows(config, input) {
|
|
43
|
+
const validationError = validateRequiredFilters(input.filters, 'Delete');
|
|
44
|
+
if (validationError !== null)
|
|
45
|
+
return Promise.resolve(validationError);
|
|
46
|
+
const url = buildMutationUrl(config.url, input.table, input.filters);
|
|
47
|
+
return requestRows(config, url, { method: 'DELETE' });
|
|
48
|
+
}
|
|
49
|
+
async function findRowById(config, input) {
|
|
50
|
+
const result = await requestRows(config, buildSelectUrl(config.url, {
|
|
51
|
+
table: input.table,
|
|
52
|
+
columns: input.columns,
|
|
53
|
+
filters: [{ field: input.idField ?? 'id', operator: 'eq', value: input.id }],
|
|
54
|
+
page: { limit: 1 },
|
|
55
|
+
schema: input.schema,
|
|
56
|
+
}), { method: 'GET' });
|
|
57
|
+
if (!result.ok)
|
|
58
|
+
return result;
|
|
59
|
+
const success = {
|
|
60
|
+
ok: true,
|
|
61
|
+
data: result.data[0] ?? null,
|
|
73
62
|
};
|
|
63
|
+
return success;
|
|
64
|
+
}
|
|
65
|
+
function insertRows(config, input) {
|
|
66
|
+
const url = buildMutationUrl(config.url, input.table, []);
|
|
67
|
+
return requestRows(config, url, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
body: JSON.stringify(input.values),
|
|
70
|
+
});
|
|
74
71
|
}
|
|
75
72
|
function normalizeConfig(options) {
|
|
76
73
|
const fetchImplementation = options.fetch ?? globalThis.fetch;
|
|
@@ -93,9 +90,8 @@ async function requestRows(config, url, init) {
|
|
|
93
90
|
headers: createHeaders(config, init.headers),
|
|
94
91
|
});
|
|
95
92
|
const body = await readJsonBody(response);
|
|
96
|
-
if (!response.ok)
|
|
93
|
+
if (!response.ok)
|
|
97
94
|
return { ok: false, error: mapHttpError(response.status, body) };
|
|
98
|
-
}
|
|
99
95
|
const records = normalizeRecords(body);
|
|
100
96
|
if (records === null) {
|
|
101
97
|
return {
|
|
@@ -112,6 +108,19 @@ async function requestRows(config, url, init) {
|
|
|
112
108
|
return { ok: false, error: mapNetworkError(error) };
|
|
113
109
|
}
|
|
114
110
|
}
|
|
111
|
+
function selectRows(config, input) {
|
|
112
|
+
return requestRows(config, buildSelectUrl(config.url, input), { method: 'GET' });
|
|
113
|
+
}
|
|
114
|
+
function updateRows(config, input) {
|
|
115
|
+
const validationError = validateRequiredFilters(input.filters, 'Update');
|
|
116
|
+
if (validationError !== null)
|
|
117
|
+
return Promise.resolve(validationError);
|
|
118
|
+
const url = buildMutationUrl(config.url, input.table, input.filters);
|
|
119
|
+
return requestRows(config, url, {
|
|
120
|
+
method: 'PATCH',
|
|
121
|
+
body: JSON.stringify(input.values),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
115
124
|
function validateRequiredFilters(filters, label) {
|
|
116
125
|
try {
|
|
117
126
|
validateFilters(filters, label);
|
|
@@ -139,9 +148,8 @@ function createHeaders(config, existingHeaders) {
|
|
|
139
148
|
}
|
|
140
149
|
async function readJsonBody(response) {
|
|
141
150
|
const text = await response.text();
|
|
142
|
-
if (text.trim().length === 0)
|
|
151
|
+
if (text.trim().length === 0)
|
|
143
152
|
return [];
|
|
144
|
-
}
|
|
145
153
|
try {
|
|
146
154
|
return JSON.parse(text);
|
|
147
155
|
}
|
|
@@ -150,12 +158,10 @@ async function readJsonBody(response) {
|
|
|
150
158
|
}
|
|
151
159
|
}
|
|
152
160
|
function normalizeRecords(value) {
|
|
153
|
-
if (Array.isArray(value))
|
|
161
|
+
if (Array.isArray(value))
|
|
154
162
|
return value.filter((isRecord));
|
|
155
|
-
|
|
156
|
-
if (isRecord(value)) {
|
|
163
|
+
if (isRecord(value))
|
|
157
164
|
return [value];
|
|
158
|
-
}
|
|
159
165
|
return null;
|
|
160
166
|
}
|
|
161
167
|
function isRecord(value) {
|
package/dist/adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DbAdapter,\n DbDeleteInput,\n DbFilter,\n DbFindByIdInput,\n DbInsertInput,\n DbRecord,\n DbResult,\n DbSelectInput,\n DbUpdateInput,\n} from '@ankhorage/contracts/db';\n\nimport { createDbError, mapHttpError, mapNetworkError } from './errors.js';\nimport { buildMutationUrl, buildSelectUrl } from './query.js';\nimport { createRealtimeApi } from './realtime.js';\nimport type { SupabaseDbAdapter, SupabaseDbAdapterOptions } from './types.js';\nimport { validateFilters, validateKey, validateUrl } from './validation.js';\n\ninterface NormalizedConfig {\n readonly url: string;\n readonly anonKey: string;\n readonly schema: string;\n readonly fetch: typeof fetch;\n readonly realtime: boolean;\n readonly realtimeClient: SupabaseDbAdapterOptions['realtimeClient'];\n}\n\ntype DbFailureResult = Extract<DbResult<unknown>, { readonly ok: false }>;\ninterface DbFindByIdSuccessResult<TRecord extends object> {\n readonly ok: true;\n readonly data: TRecord | null;\n}\n\nexport function createSupabaseDbAdapter(options: SupabaseDbAdapterOptions): SupabaseDbAdapter {\n const config = normalizeConfig(options);\n const baseAdapter: DbAdapter = {\n capabilities: {\n transactions: false,\n returning: true,\n realtime: config.realtime && config.realtimeClient !== undefined,\n },\n\n async select<TRecord extends object = DbRecord>(\n input: DbSelectInput,\n ): Promise<DbResult<TRecord[]>> {\n return requestRows<TRecord>(config, buildSelectUrl(config.url, input), {\n method: 'GET',\n });\n },\n\n async findById<TRecord extends object = DbRecord>(\n input: DbFindByIdInput,\n ): Promise<DbResult<TRecord | null>> {\n const result = await requestRows<TRecord>(\n config,\n buildSelectUrl(config.url, {\n table: input.table,\n columns: input.columns,\n filters: [{ field: input.idField ?? 'id', operator: 'eq', value: input.id }],\n page: { limit: 1 },\n schema: input.schema,\n }),\n { method: 'GET' },\n );\n\n if (!result.ok) {\n return result;\n }\n\n const success: DbFindByIdSuccessResult<TRecord> = {\n ok: true,\n data: result.data[0] ?? null,\n };\n\n return success;\n },\n\n async insert<TRecord extends object = DbRecord>(\n input: DbInsertInput<TRecord>,\n ): Promise<DbResult<TRecord[]>> {\n const url = buildMutationUrl(config.url, input.table, []);\n\n return requestRows<TRecord>(config, url, {\n method: 'POST',\n body: JSON.stringify(input.values),\n });\n },\n\n async update<TRecord extends object = DbRecord>(\n input: DbUpdateInput<TRecord>,\n ): Promise<DbResult<TRecord[]>> {\n const validationError = validateRequiredFilters(input.filters, 'Update');\n\n if (validationError !== null) {\n return validationError;\n }\n\n const url = buildMutationUrl(config.url, input.table, input.filters);\n\n return requestRows<TRecord>(config, url, {\n method: 'PATCH',\n body: JSON.stringify(input.values),\n });\n },\n\n async delete<TRecord extends object = DbRecord>(\n input: DbDeleteInput,\n ): Promise<DbResult<TRecord[]>> {\n const validationError = validateRequiredFilters(input.filters, 'Delete');\n\n if (validationError !== null) {\n return validationError;\n }\n\n const url = buildMutationUrl(config.url, input.table, input.filters);\n\n return requestRows<TRecord>(config, url, {\n method: 'DELETE',\n });\n },\n };\n\n if (!config.realtime || config.realtimeClient === undefined) {\n return baseAdapter;\n }\n\n return {\n ...baseAdapter,\n realtime: createRealtimeApi({\n client: config.realtimeClient,\n defaultSchema: config.schema,\n }),\n };\n}\n\nfunction normalizeConfig(options: SupabaseDbAdapterOptions): NormalizedConfig {\n const fetchImplementation = options.fetch ?? globalThis.fetch;\n\n if (typeof fetchImplementation !== 'function') {\n throw new TypeError('A fetch implementation is required to use Supabase Database.');\n }\n\n return {\n url: validateUrl(options.url),\n anonKey: validateKey(options.anonKey, 'Supabase anon key'),\n schema: options.schema ?? 'public',\n fetch: fetchImplementation,\n realtime: options.realtime ?? false,\n realtimeClient: options.realtimeClient,\n };\n}\n\nasync function requestRows<TRecord extends object>(\n config: NormalizedConfig,\n url: URL,\n init: RequestInit,\n): Promise<DbResult<TRecord[]>> {\n try {\n const response = await config.fetch(url, {\n ...init,\n headers: createHeaders(config, init.headers),\n });\n const body = await readJsonBody(response);\n\n if (!response.ok) {\n return { ok: false, error: mapHttpError(response.status, body) };\n }\n\n const records = normalizeRecords<TRecord>(body);\n\n if (records === null) {\n return {\n ok: false,\n error: createDbError(\n 'provider_error',\n 'Supabase Database returned an invalid records response.',\n body,\n ),\n };\n }\n\n return { ok: true, data: records };\n } catch (error) {\n if (error instanceof TypeError) {\n return { ok: false, error: createDbError('validation_error', error.message, error) };\n }\n\n return { ok: false, error: mapNetworkError(error) };\n }\n}\n\nfunction validateRequiredFilters(\n filters: readonly DbFilter[],\n label: string,\n): DbFailureResult | null {\n try {\n validateFilters(filters, label);\n return null;\n } catch (error) {\n return {\n ok: false,\n error: createDbError(\n 'validation_error',\n error instanceof Error ? error.message : `${label} filters are invalid.`,\n error,\n ),\n };\n }\n}\n\nfunction createHeaders(\n config: NormalizedConfig,\n existingHeaders: HeadersInit | undefined,\n): Headers {\n const headers = new Headers(existingHeaders);\n\n headers.set('apikey', config.anonKey);\n headers.set('Authorization', `Bearer ${config.anonKey}`);\n headers.set('Accept', 'application/json');\n headers.set('Content-Type', 'application/json');\n headers.set('Prefer', 'return=representation');\n\n if (config.schema !== 'public') {\n headers.set('Accept-Profile', config.schema);\n headers.set('Content-Profile', config.schema);\n }\n\n return headers;\n}\n\nasync function readJsonBody(response: Response): Promise<unknown> {\n const text = await response.text();\n\n if (text.trim().length === 0) {\n return [];\n }\n\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction normalizeRecords<TRecord extends object>(value: unknown): TRecord[] | null {\n if (Array.isArray(value)) {\n return value.filter(isRecord<TRecord>);\n }\n\n if (isRecord<TRecord>(value)) {\n return [value];\n }\n\n return null;\n}\n\nfunction isRecord<TRecord extends object>(value: unknown): value is TRecord {\n return typeof value === 'object' && value !== null;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DbAdapter,\n DbDeleteInput,\n DbFilter,\n DbFindByIdInput,\n DbInsertInput,\n DbRecord,\n DbResult,\n DbSelectInput,\n DbUpdateInput,\n} from '@ankhorage/contracts/db';\n\nimport { createDbError, mapHttpError, mapNetworkError } from './errors.js';\nimport { buildMutationUrl, buildSelectUrl } from './query.js';\nimport { createRealtimeApi } from './realtime.js';\nimport type { SupabaseDbAdapter, SupabaseDbAdapterOptions } from './types.js';\nimport { validateFilters, validateKey, validateUrl } from './validation.js';\n\ninterface NormalizedConfig {\n readonly url: string;\n readonly anonKey: string;\n readonly schema: string;\n readonly fetch: typeof fetch;\n readonly realtime: boolean;\n readonly realtimeClient: SupabaseDbAdapterOptions['realtimeClient'];\n}\n\ntype DbFailureResult = Extract<DbResult<unknown>, { readonly ok: false }>;\ninterface DbFindByIdSuccessResult<TRecord extends object> {\n readonly ok: true;\n readonly data: TRecord | null;\n}\n\nexport function createSupabaseDbAdapter(options: SupabaseDbAdapterOptions): SupabaseDbAdapter {\n const config = normalizeConfig(options);\n const baseAdapter = createBaseAdapter(config);\n if (!config.realtime || config.realtimeClient === undefined) return baseAdapter;\n return {\n ...baseAdapter,\n realtime: createRealtimeApi({\n client: config.realtimeClient,\n defaultSchema: config.schema,\n }),\n };\n}\n\nfunction createBaseAdapter(config: NormalizedConfig): DbAdapter {\n return {\n capabilities: {\n transactions: false,\n returning: true,\n realtime: config.realtime && config.realtimeClient !== undefined,\n },\n select<TRecord extends object = DbRecord>(input: DbSelectInput) {\n return selectRows<TRecord>(config, input);\n },\n findById<TRecord extends object = DbRecord>(input: DbFindByIdInput) {\n return findRowById<TRecord>(config, input);\n },\n insert<TRecord extends object = DbRecord>(input: DbInsertInput<TRecord>) {\n return insertRows<TRecord>(config, input);\n },\n update<TRecord extends object = DbRecord>(input: DbUpdateInput<TRecord>) {\n return updateRows<TRecord>(config, input);\n },\n delete<TRecord extends object = DbRecord>(input: DbDeleteInput) {\n return deleteRows<TRecord>(config, input);\n },\n };\n}\n\nfunction deleteRows<TRecord extends object>(\n config: NormalizedConfig,\n input: DbDeleteInput,\n): Promise<DbResult<TRecord[]>> {\n const validationError = validateRequiredFilters(input.filters, 'Delete');\n if (validationError !== null) return Promise.resolve(validationError);\n const url = buildMutationUrl(config.url, input.table, input.filters);\n return requestRows<TRecord>(config, url, { method: 'DELETE' });\n}\n\nasync function findRowById<TRecord extends object>(\n config: NormalizedConfig,\n input: DbFindByIdInput,\n): Promise<DbResult<TRecord | null>> {\n const result = await requestRows<TRecord>(\n config,\n buildSelectUrl(config.url, {\n table: input.table,\n columns: input.columns,\n filters: [{ field: input.idField ?? 'id', operator: 'eq', value: input.id }],\n page: { limit: 1 },\n schema: input.schema,\n }),\n { method: 'GET' },\n );\n if (!result.ok) return result;\n const success: DbFindByIdSuccessResult<TRecord> = {\n ok: true,\n data: result.data[0] ?? null,\n };\n return success;\n}\n\nfunction insertRows<TRecord extends object>(\n config: NormalizedConfig,\n input: DbInsertInput<TRecord>,\n): Promise<DbResult<TRecord[]>> {\n const url = buildMutationUrl(config.url, input.table, []);\n return requestRows<TRecord>(config, url, {\n method: 'POST',\n body: JSON.stringify(input.values),\n });\n}\n\nfunction normalizeConfig(options: SupabaseDbAdapterOptions): NormalizedConfig {\n const fetchImplementation = options.fetch ?? globalThis.fetch;\n if (typeof fetchImplementation !== 'function') {\n throw new TypeError('A fetch implementation is required to use Supabase Database.');\n }\n return {\n url: validateUrl(options.url),\n anonKey: validateKey(options.anonKey, 'Supabase anon key'),\n schema: options.schema ?? 'public',\n fetch: fetchImplementation,\n realtime: options.realtime ?? false,\n realtimeClient: options.realtimeClient,\n };\n}\n\nasync function requestRows<TRecord extends object>(\n config: NormalizedConfig,\n url: URL,\n init: RequestInit,\n): Promise<DbResult<TRecord[]>> {\n try {\n const response = await config.fetch(url, {\n ...init,\n headers: createHeaders(config, init.headers),\n });\n const body = await readJsonBody(response);\n if (!response.ok) return { ok: false, error: mapHttpError(response.status, body) };\n const records = normalizeRecords<TRecord>(body);\n if (records === null) {\n return {\n ok: false,\n error: createDbError(\n 'provider_error',\n 'Supabase Database returned an invalid records response.',\n body,\n ),\n };\n }\n return { ok: true, data: records };\n } catch (error) {\n if (error instanceof TypeError) {\n return { ok: false, error: createDbError('validation_error', error.message, error) };\n }\n return { ok: false, error: mapNetworkError(error) };\n }\n}\n\nfunction selectRows<TRecord extends object>(\n config: NormalizedConfig,\n input: DbSelectInput,\n): Promise<DbResult<TRecord[]>> {\n return requestRows<TRecord>(config, buildSelectUrl(config.url, input), { method: 'GET' });\n}\n\nfunction updateRows<TRecord extends object>(\n config: NormalizedConfig,\n input: DbUpdateInput<TRecord>,\n): Promise<DbResult<TRecord[]>> {\n const validationError = validateRequiredFilters(input.filters, 'Update');\n if (validationError !== null) return Promise.resolve(validationError);\n const url = buildMutationUrl(config.url, input.table, input.filters);\n return requestRows<TRecord>(config, url, {\n method: 'PATCH',\n body: JSON.stringify(input.values),\n });\n}\n\nfunction validateRequiredFilters(\n filters: readonly DbFilter[],\n label: string,\n): DbFailureResult | null {\n try {\n validateFilters(filters, label);\n return null;\n } catch (error) {\n return {\n ok: false,\n error: createDbError(\n 'validation_error',\n error instanceof Error ? error.message : `${label} filters are invalid.`,\n error,\n ),\n };\n }\n}\n\nfunction createHeaders(\n config: NormalizedConfig,\n existingHeaders: HeadersInit | undefined,\n): Headers {\n const headers = new Headers(existingHeaders);\n headers.set('apikey', config.anonKey);\n headers.set('Authorization', `Bearer ${config.anonKey}`);\n headers.set('Accept', 'application/json');\n headers.set('Content-Type', 'application/json');\n headers.set('Prefer', 'return=representation');\n if (config.schema !== 'public') {\n headers.set('Accept-Profile', config.schema);\n headers.set('Content-Profile', config.schema);\n }\n return headers;\n}\n\nasync function readJsonBody(response: Response): Promise<unknown> {\n const text = await response.text();\n if (text.trim().length === 0) return [];\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction normalizeRecords<TRecord extends object>(value: unknown): TRecord[] | null {\n if (Array.isArray(value)) return value.filter(isRecord<TRecord>);\n if (isRecord<TRecord>(value)) return [value];\n return null;\n}\n\nfunction isRecord<TRecord extends object>(value: unknown): value is TRecord {\n return typeof value === 'object' && value !== null;\n}\n"]}
|
package/dist/realtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAIb,iBAAiB,EACjB,QAAQ,EAGT,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAGlF,UAAU,iBAAiB;IACzB,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAIb,iBAAiB,EACjB,QAAQ,EAGT,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAGlF,UAAU,iBAAiB;IACzB,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAe1F;AAED,wBAAgB,sBAAsB,CAAC,OAAO,SAAS,MAAM,GAAG,QAAQ,EACtE,OAAO,EAAE,uBAAuB,EAChC,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,GACrB,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAc/B"}
|
package/dist/realtime.js
CHANGED
|
@@ -2,58 +2,17 @@ import { validateIdentifier } from './validation.js';
|
|
|
2
2
|
export function createRealtimeApi(config) {
|
|
3
3
|
return {
|
|
4
4
|
subscribeToCollection(input, listener) {
|
|
5
|
-
|
|
6
|
-
const table = validateIdentifier(input.table, 'Realtime table');
|
|
7
|
-
const channel = config.client
|
|
8
|
-
.channel(`ankhorage-db:${schema}:${table}`)
|
|
9
|
-
.on('postgres_changes', {
|
|
10
|
-
event: '*',
|
|
11
|
-
schema,
|
|
12
|
-
table,
|
|
13
|
-
}, (payload) => {
|
|
14
|
-
const event = normalizeRealtimeEvent(payload, table, schema);
|
|
15
|
-
if (event !== null) {
|
|
16
|
-
listener(event);
|
|
17
|
-
}
|
|
18
|
-
})
|
|
19
|
-
.subscribe();
|
|
20
|
-
return {
|
|
21
|
-
async unsubscribe() {
|
|
22
|
-
await config.client.removeChannel(channel);
|
|
23
|
-
},
|
|
24
|
-
};
|
|
5
|
+
return createCollectionSubscription(config, input, listener);
|
|
25
6
|
},
|
|
26
7
|
subscribeToRecord(input, listener) {
|
|
27
|
-
|
|
28
|
-
const table = validateIdentifier(input.table, 'Realtime table');
|
|
29
|
-
const idField = validateIdentifier(input.idField ?? 'id', 'Realtime record id field');
|
|
30
|
-
const channel = config.client
|
|
31
|
-
.channel(`ankhorage-db:${schema}:${table}:${idField}:${String(input.id)}`)
|
|
32
|
-
.on('postgres_changes', {
|
|
33
|
-
event: '*',
|
|
34
|
-
schema,
|
|
35
|
-
table,
|
|
36
|
-
filter: `${idField}=eq.${String(input.id)}`,
|
|
37
|
-
}, (payload) => {
|
|
38
|
-
const event = normalizeRealtimeEvent(payload, table, schema);
|
|
39
|
-
if (event !== null) {
|
|
40
|
-
listener(event);
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
.subscribe();
|
|
44
|
-
return {
|
|
45
|
-
async unsubscribe() {
|
|
46
|
-
await config.client.removeChannel(channel);
|
|
47
|
-
},
|
|
48
|
-
};
|
|
8
|
+
return createRecordSubscription(config, input, listener);
|
|
49
9
|
},
|
|
50
10
|
};
|
|
51
11
|
}
|
|
52
12
|
export function normalizeRealtimeEvent(payload, fallbackTable, fallbackSchema) {
|
|
53
13
|
const kind = normalizeKind(payload.eventType);
|
|
54
|
-
if (kind === null)
|
|
14
|
+
if (kind === null)
|
|
55
15
|
return null;
|
|
56
|
-
}
|
|
57
16
|
const record = normalizeRecord(payload.new);
|
|
58
17
|
const previousRecord = normalizeRecord(payload.old);
|
|
59
18
|
const base = {
|
|
@@ -63,14 +22,40 @@ export function normalizeRealtimeEvent(payload, fallbackTable, fallbackSchema) {
|
|
|
63
22
|
record: kind === 'delete' ? null : record,
|
|
64
23
|
committedAt: payload.commit_timestamp,
|
|
65
24
|
};
|
|
66
|
-
if (previousRecord === null)
|
|
25
|
+
if (previousRecord === null)
|
|
67
26
|
return base;
|
|
68
|
-
}
|
|
27
|
+
return { ...base, previousRecord };
|
|
28
|
+
}
|
|
29
|
+
function createCollectionSubscription(config, input, listener) {
|
|
30
|
+
const schema = input.schema ?? config.defaultSchema;
|
|
31
|
+
const table = validateIdentifier(input.table, 'Realtime table');
|
|
32
|
+
return createSubscription(config, `ankhorage-db:${schema}:${table}`, schema, table, listener);
|
|
33
|
+
}
|
|
34
|
+
function createRecordSubscription(config, input, listener) {
|
|
35
|
+
const schema = input.schema ?? config.defaultSchema;
|
|
36
|
+
const table = validateIdentifier(input.table, 'Realtime table');
|
|
37
|
+
const idField = validateIdentifier(input.idField ?? 'id', 'Realtime record id field');
|
|
38
|
+
const id = String(input.id);
|
|
39
|
+
return createSubscription(config, `ankhorage-db:${schema}:${table}:${idField}:${id}`, schema, table, listener, `${idField}=eq.${id}`);
|
|
40
|
+
}
|
|
41
|
+
function createSubscription(config, channelName, schema, table, listener, filter) {
|
|
42
|
+
const channel = config.client
|
|
43
|
+
.channel(channelName)
|
|
44
|
+
.on('postgres_changes', { event: '*', schema, table, filter }, (payload) => {
|
|
45
|
+
const event = normalizeRealtimeEvent(payload, table, schema);
|
|
46
|
+
if (event !== null)
|
|
47
|
+
listener(event);
|
|
48
|
+
})
|
|
49
|
+
.subscribe();
|
|
69
50
|
return {
|
|
70
|
-
|
|
71
|
-
|
|
51
|
+
async unsubscribe() {
|
|
52
|
+
await config.client.removeChannel(channel);
|
|
53
|
+
},
|
|
72
54
|
};
|
|
73
55
|
}
|
|
56
|
+
function isRecord(value) {
|
|
57
|
+
return typeof value === 'object' && value !== null;
|
|
58
|
+
}
|
|
74
59
|
function normalizeKind(value) {
|
|
75
60
|
switch (value) {
|
|
76
61
|
case 'INSERT':
|
|
@@ -84,12 +69,6 @@ function normalizeKind(value) {
|
|
|
84
69
|
}
|
|
85
70
|
}
|
|
86
71
|
function normalizeRecord(value) {
|
|
87
|
-
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
return value;
|
|
91
|
-
}
|
|
92
|
-
function isRecord(value) {
|
|
93
|
-
return typeof value === 'object' && value !== null;
|
|
72
|
+
return isRecord(value) ? value : null;
|
|
94
73
|
}
|
|
95
74
|
//# sourceMappingURL=realtime.js.map
|
package/dist/realtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime.js","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAOrD,MAAM,UAAU,iBAAiB,CAAC,MAAyB;IACzD,OAAO;QACL,qBAAqB,CACnB,KAAoC,EACpC,QAAmC;YAEnC,
|
|
1
|
+
{"version":3,"file":"realtime.js","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DbChangeEvent,\n DbChangeKind,\n DbChangeListener,\n DbCollectionSubscriptionInput,\n DbRealtimeAdapter,\n DbRecord,\n DbRecordSubscriptionInput,\n DbSubscription,\n} from '@ankhorage/contracts/db';\n\nimport type { SupabaseRealtimeClient, SupabaseRealtimePayload } from './types.js';\nimport { validateIdentifier } from './validation.js';\n\ninterface RealtimeApiConfig {\n readonly client: SupabaseRealtimeClient;\n readonly defaultSchema: string;\n}\n\nexport function createRealtimeApi(config: RealtimeApiConfig): DbRealtimeAdapter['realtime'] {\n return {\n subscribeToCollection<TRecord extends object = DbRecord>(\n input: DbCollectionSubscriptionInput,\n listener: DbChangeListener<TRecord>,\n ): DbSubscription {\n return createCollectionSubscription(config, input, listener);\n },\n subscribeToRecord<TRecord extends object = DbRecord>(\n input: DbRecordSubscriptionInput,\n listener: DbChangeListener<TRecord>,\n ): DbSubscription {\n return createRecordSubscription(config, input, listener);\n },\n };\n}\n\nexport function normalizeRealtimeEvent<TRecord extends object = DbRecord>(\n payload: SupabaseRealtimePayload,\n fallbackTable: string,\n fallbackSchema: string,\n): DbChangeEvent<TRecord> | null {\n const kind = normalizeKind(payload.eventType);\n if (kind === null) return null;\n const record = normalizeRecord<TRecord>(payload.new);\n const previousRecord = normalizeRecord<TRecord>(payload.old);\n const base = {\n table: payload.table ?? fallbackTable,\n schema: payload.schema ?? fallbackSchema,\n kind,\n record: kind === 'delete' ? null : record,\n committedAt: payload.commit_timestamp,\n };\n if (previousRecord === null) return base;\n return { ...base, previousRecord };\n}\n\nfunction createCollectionSubscription<TRecord extends object>(\n config: RealtimeApiConfig,\n input: DbCollectionSubscriptionInput,\n listener: DbChangeListener<TRecord>,\n): DbSubscription {\n const schema = input.schema ?? config.defaultSchema;\n const table = validateIdentifier(input.table, 'Realtime table');\n return createSubscription(config, `ankhorage-db:${schema}:${table}`, schema, table, listener);\n}\n\nfunction createRecordSubscription<TRecord extends object>(\n config: RealtimeApiConfig,\n input: DbRecordSubscriptionInput,\n listener: DbChangeListener<TRecord>,\n): DbSubscription {\n const schema = input.schema ?? config.defaultSchema;\n const table = validateIdentifier(input.table, 'Realtime table');\n const idField = validateIdentifier(input.idField ?? 'id', 'Realtime record id field');\n const id = String(input.id);\n return createSubscription(\n config,\n `ankhorage-db:${schema}:${table}:${idField}:${id}`,\n schema,\n table,\n listener,\n `${idField}=eq.${id}`,\n );\n}\n\nfunction createSubscription<TRecord extends object>(\n config: RealtimeApiConfig,\n channelName: string,\n schema: string,\n table: string,\n listener: DbChangeListener<TRecord>,\n filter?: string,\n): DbSubscription {\n const channel = config.client\n .channel(channelName)\n .on('postgres_changes', { event: '*', schema, table, filter }, (payload) => {\n const event = normalizeRealtimeEvent<TRecord>(payload, table, schema);\n if (event !== null) listener(event);\n })\n .subscribe();\n return {\n async unsubscribe(): Promise<void> {\n await config.client.removeChannel(channel);\n },\n };\n}\n\nfunction isRecord<TRecord extends object>(value: unknown): value is TRecord {\n return typeof value === 'object' && value !== null;\n}\n\nfunction normalizeKind(value: string | undefined): DbChangeKind | null {\n switch (value) {\n case 'INSERT':\n return 'insert';\n case 'UPDATE':\n return 'update';\n case 'DELETE':\n return 'delete';\n default:\n return null;\n }\n}\n\nfunction normalizeRecord<TRecord extends object>(value: unknown): TRecord | null {\n return isRecord<TRecord>(value) ? value : null;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/supabase-db",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.3",
|
|
5
5
|
"description": "Supabase database adapter for Ankhorage contracts with CRUD, schema management, and optional realtime support.",
|
|
6
6
|
"homepage": "https://github.com/ankhorage/supabase-db#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"adapter"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@ankhorage/contracts": "^8.0.
|
|
28
|
+
"@ankhorage/contracts": "^8.0.2"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"@supabase/supabase-js": "^2.105.3"
|
|
@@ -56,10 +56,9 @@
|
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "rm -rf dist tsconfig.tsbuildinfo && bun x tsc -p tsconfig.json",
|
|
59
|
-
"changeset": "changeset",
|
|
60
|
-
"changeset:status": "changeset status --since=origin/main",
|
|
59
|
+
"changeset": "ankhorage-changeset",
|
|
60
|
+
"changeset:status": "ankhorage-changeset status --since=origin/main",
|
|
61
61
|
"docs": "paradox",
|
|
62
|
-
"knip": "knip",
|
|
63
62
|
"lint": "ankhorage-eslint . --max-warnings=0",
|
|
64
63
|
"lint:fix": "ankhorage-eslint . --fix --max-warnings=0",
|
|
65
64
|
"format": "ankhorage-prettier --write .",
|
|
@@ -67,16 +66,15 @@
|
|
|
67
66
|
"prepack": "bun run build",
|
|
68
67
|
"test": "bun test src",
|
|
69
68
|
"typecheck": "bun x tsc --noEmit -p tsconfig.json",
|
|
70
|
-
"version-packages": "changeset version"
|
|
69
|
+
"version-packages": "ankhorage-changeset version",
|
|
70
|
+
"knip:check": "ankhorage-knip"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
|
-
"@ankhorage/devtools": "^1.
|
|
74
|
-
"@ankhorage/paradox": "^0.1.
|
|
75
|
-
"@
|
|
76
|
-
"@types/bun": "^1.3.13",
|
|
73
|
+
"@ankhorage/devtools": "^1.9.4",
|
|
74
|
+
"@ankhorage/paradox": "^0.1.24",
|
|
75
|
+
"@types/bun": "^1.4.0",
|
|
77
76
|
"@types/node": "^25.6.0",
|
|
78
|
-
"knip": "^6.12.2",
|
|
79
77
|
"typescript": "^5.9.3"
|
|
80
78
|
},
|
|
81
|
-
"packageManager": "bun@1.
|
|
79
|
+
"packageManager": "bun@1.4.0"
|
|
82
80
|
}
|