@xylex-group/better-auth-athena 1.0.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.
- package/CONTRIBUTING.md +28 -0
- package/CONTRIBUTORS.md +3 -0
- package/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/index.cjs +216 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +52 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +193 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for taking the time to contribute to **better-auth-athena**!
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
1. Fork and clone the repository.
|
|
8
|
+
2. Install dependencies:
|
|
9
|
+
```bash
|
|
10
|
+
npm install
|
|
11
|
+
```
|
|
12
|
+
3. Run the checks:
|
|
13
|
+
```bash
|
|
14
|
+
npm run typecheck
|
|
15
|
+
npm run test
|
|
16
|
+
npm run build
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Pull Requests
|
|
20
|
+
|
|
21
|
+
- Keep changes focused and scoped to a single issue.
|
|
22
|
+
- Add or update tests when you change behavior.
|
|
23
|
+
- Ensure `npm run typecheck`, `npm run test`, and `npm run build` succeed before requesting review.
|
|
24
|
+
- Describe the motivation and context in the PR description.
|
|
25
|
+
|
|
26
|
+
## Reporting Issues
|
|
27
|
+
|
|
28
|
+
If you find a bug, please open an issue with clear reproduction steps, expected behavior, and actual behavior.
|
package/CONTRIBUTORS.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 XYLEX GROUP
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# better-auth-athena
|
|
2
|
+
|
|
3
|
+
A Better-Auth database adapter for the `@xylex-group/athena` gateway. It lets Better-Auth read and write data through Athena while keeping column names in `snake_case` as required by the gateway.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install better-auth-athena
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This package relies on the following peer dependencies, so ensure they are installed in your project:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install better-auth @xylex-group/athena
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { betterAuth } from "better-auth";
|
|
21
|
+
import { athenaAdapter } from "better-auth-athena";
|
|
22
|
+
|
|
23
|
+
export const auth = betterAuth({
|
|
24
|
+
database: athenaAdapter({
|
|
25
|
+
url: process.env.ATHENA_URL!,
|
|
26
|
+
apiKey: process.env.ATHENA_API_KEY!,
|
|
27
|
+
client: "my-app",
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Configuration
|
|
33
|
+
|
|
34
|
+
`athenaAdapter` accepts the following options:
|
|
35
|
+
|
|
36
|
+
| Option | Type | Required | Default | Description |
|
|
37
|
+
| --- | --- | --- | --- | --- |
|
|
38
|
+
| `url` | `string` | ✅ | — | Athena gateway URL. |
|
|
39
|
+
| `apiKey` | `string` | ✅ | — | API key used to authenticate with Athena. |
|
|
40
|
+
| `client` | `string` | ❌ | — | Client name included with gateway requests. |
|
|
41
|
+
| `debugLogs` | `DBAdapterDebugLogOption` | ❌ | `false` | Enables Better-Auth adapter debug logs. |
|
|
42
|
+
| `usePlural` | `boolean` | ❌ | `false` | Treats table names as plural when mapping models. |
|
|
43
|
+
|
|
44
|
+
## Notes
|
|
45
|
+
|
|
46
|
+
- `findMany` sorting is performed in memory because the Athena SDK does not expose an order-by method on its query builder.
|
|
47
|
+
- The adapter enables JSON, date, boolean, and numeric ID support in Better-Auth.
|
|
48
|
+
|
|
49
|
+
## Development
|
|
50
|
+
|
|
51
|
+
Node.js 20.19.0 or later is required for the test/build tooling.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm run typecheck
|
|
55
|
+
npm run test
|
|
56
|
+
npm run build
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## CI/CD
|
|
60
|
+
|
|
61
|
+
GitHub Actions runs the typecheck, test, and build steps for every pull request and push. Releases can be published to npm by creating a GitHub release after the CI workflow succeeds.
|
|
62
|
+
|
|
63
|
+
## Contributing
|
|
64
|
+
|
|
65
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup steps and the contribution process.
|
|
66
|
+
|
|
67
|
+
## Contributors
|
|
68
|
+
|
|
69
|
+
See [CONTRIBUTORS.md](./CONTRIBUTORS.md) for the current list of project contributors.
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
athenaAdapter: () => athenaAdapter
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
var import_adapters = require("better-auth/adapters");
|
|
27
|
+
var import_athena = require("@xylex-group/athena");
|
|
28
|
+
function applyWhere(builder, field, operator, value) {
|
|
29
|
+
switch (operator) {
|
|
30
|
+
case "eq":
|
|
31
|
+
return builder.eq(field, value);
|
|
32
|
+
case "ne":
|
|
33
|
+
return builder.neq(field, value);
|
|
34
|
+
case "gt":
|
|
35
|
+
return builder.gt(field, value);
|
|
36
|
+
case "gte":
|
|
37
|
+
return builder.gte(field, value);
|
|
38
|
+
case "lt":
|
|
39
|
+
return builder.lt(field, value);
|
|
40
|
+
case "lte":
|
|
41
|
+
return builder.lte(field, value);
|
|
42
|
+
case "in":
|
|
43
|
+
return builder.in(field, value);
|
|
44
|
+
case "not_in":
|
|
45
|
+
return builder.not(field, "in", value);
|
|
46
|
+
case "contains":
|
|
47
|
+
return builder.like(field, `%${value}%`);
|
|
48
|
+
case "starts_with":
|
|
49
|
+
return builder.like(field, `${value}%`);
|
|
50
|
+
case "ends_with":
|
|
51
|
+
return builder.like(field, `%${value}`);
|
|
52
|
+
default:
|
|
53
|
+
return builder.eq(field, value);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
var athenaAdapter = (config) => {
|
|
57
|
+
const db = (0, import_athena.createClient)(config.url, config.apiKey, {
|
|
58
|
+
client: config.client
|
|
59
|
+
});
|
|
60
|
+
return (0, import_adapters.createAdapterFactory)({
|
|
61
|
+
config: {
|
|
62
|
+
adapterId: "athena",
|
|
63
|
+
adapterName: "Athena Adapter",
|
|
64
|
+
usePlural: config.usePlural ?? false,
|
|
65
|
+
debugLogs: config.debugLogs ?? false,
|
|
66
|
+
// Athena/Postgres supports all these natively
|
|
67
|
+
supportsJSON: true,
|
|
68
|
+
supportsDates: true,
|
|
69
|
+
supportsBooleans: true,
|
|
70
|
+
supportsNumericIds: true
|
|
71
|
+
},
|
|
72
|
+
adapter: () => {
|
|
73
|
+
return {
|
|
74
|
+
// ------------------------------------------------------------------
|
|
75
|
+
// CREATE
|
|
76
|
+
// ------------------------------------------------------------------
|
|
77
|
+
create: async ({ model, data }) => {
|
|
78
|
+
const { data: result, error } = await db.from(model).insert(data).select();
|
|
79
|
+
if (error) {
|
|
80
|
+
throw new Error(`[AthenaAdapter] create on "${model}" failed: ${error}`);
|
|
81
|
+
}
|
|
82
|
+
const row = Array.isArray(result) ? result[0] : result;
|
|
83
|
+
return row ?? data;
|
|
84
|
+
},
|
|
85
|
+
// ------------------------------------------------------------------
|
|
86
|
+
// UPDATE
|
|
87
|
+
// ------------------------------------------------------------------
|
|
88
|
+
update: async ({ model, where, update }) => {
|
|
89
|
+
let builder = db.from(model).update(update);
|
|
90
|
+
for (const clause of where) {
|
|
91
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
92
|
+
}
|
|
93
|
+
const { data: result, error } = await builder.select();
|
|
94
|
+
if (error) {
|
|
95
|
+
throw new Error(`[AthenaAdapter] update on "${model}" failed: ${error}`);
|
|
96
|
+
}
|
|
97
|
+
const row = Array.isArray(result) ? result[0] : result;
|
|
98
|
+
return row ?? null;
|
|
99
|
+
},
|
|
100
|
+
// ------------------------------------------------------------------
|
|
101
|
+
// UPDATE MANY
|
|
102
|
+
// ------------------------------------------------------------------
|
|
103
|
+
updateMany: async ({ model, where, update }) => {
|
|
104
|
+
let builder = db.from(model).update(update);
|
|
105
|
+
for (const clause of where) {
|
|
106
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
107
|
+
}
|
|
108
|
+
const { data: result, error } = await builder.select();
|
|
109
|
+
if (error) {
|
|
110
|
+
throw new Error(`[AthenaAdapter] updateMany on "${model}" failed: ${error}`);
|
|
111
|
+
}
|
|
112
|
+
return Array.isArray(result) ? result.length : result ? 1 : 0;
|
|
113
|
+
},
|
|
114
|
+
// ------------------------------------------------------------------
|
|
115
|
+
// DELETE
|
|
116
|
+
// ------------------------------------------------------------------
|
|
117
|
+
delete: async ({ model, where }) => {
|
|
118
|
+
let builder = db.from(model);
|
|
119
|
+
for (const clause of where) {
|
|
120
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
121
|
+
}
|
|
122
|
+
const { error } = await builder.delete();
|
|
123
|
+
if (error) {
|
|
124
|
+
throw new Error(`[AthenaAdapter] delete on "${model}" failed: ${error}`);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
// ------------------------------------------------------------------
|
|
128
|
+
// DELETE MANY
|
|
129
|
+
// ------------------------------------------------------------------
|
|
130
|
+
deleteMany: async ({ model, where }) => {
|
|
131
|
+
let builder = db.from(model);
|
|
132
|
+
for (const clause of where) {
|
|
133
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
134
|
+
}
|
|
135
|
+
const { data: result, error } = await builder.delete().select();
|
|
136
|
+
if (error) {
|
|
137
|
+
throw new Error(`[AthenaAdapter] deleteMany on "${model}" failed: ${error}`);
|
|
138
|
+
}
|
|
139
|
+
return Array.isArray(result) ? result.length : result ? 1 : 0;
|
|
140
|
+
},
|
|
141
|
+
// ------------------------------------------------------------------
|
|
142
|
+
// FIND ONE
|
|
143
|
+
// ------------------------------------------------------------------
|
|
144
|
+
findOne: async ({ model, where, select }) => {
|
|
145
|
+
const columns = select && select.length > 0 ? select.join(", ") : void 0;
|
|
146
|
+
let builder = db.from(model).select(columns);
|
|
147
|
+
for (const clause of where) {
|
|
148
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
149
|
+
}
|
|
150
|
+
const { data: result, error } = await builder.limit(1);
|
|
151
|
+
if (error) {
|
|
152
|
+
throw new Error(`[AthenaAdapter] findOne on "${model}" failed: ${error}`);
|
|
153
|
+
}
|
|
154
|
+
const rows = Array.isArray(result) ? result : result ? [result] : [];
|
|
155
|
+
return rows[0] ?? null;
|
|
156
|
+
},
|
|
157
|
+
// ------------------------------------------------------------------
|
|
158
|
+
// FIND MANY
|
|
159
|
+
// ------------------------------------------------------------------
|
|
160
|
+
findMany: async ({ model, where, limit, sortBy, offset, select }) => {
|
|
161
|
+
const columns = select && select.length > 0 ? select.join(", ") : void 0;
|
|
162
|
+
let builder = db.from(model).select(columns);
|
|
163
|
+
if (where) {
|
|
164
|
+
for (const clause of where) {
|
|
165
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (limit !== void 0) {
|
|
169
|
+
builder = builder.limit(limit);
|
|
170
|
+
}
|
|
171
|
+
if (offset !== void 0) {
|
|
172
|
+
builder = builder.offset(offset);
|
|
173
|
+
}
|
|
174
|
+
const { data: result, error } = await builder;
|
|
175
|
+
if (error) {
|
|
176
|
+
throw new Error(`[AthenaAdapter] findMany on "${model}" failed: ${error}`);
|
|
177
|
+
}
|
|
178
|
+
const rows = Array.isArray(result) ? result : [];
|
|
179
|
+
if (sortBy) {
|
|
180
|
+
rows.sort((a, b) => {
|
|
181
|
+
const aVal = a[sortBy.field];
|
|
182
|
+
const bVal = b[sortBy.field];
|
|
183
|
+
if (aVal == null && bVal == null) return 0;
|
|
184
|
+
if (aVal == null) return sortBy.direction === "asc" ? -1 : 1;
|
|
185
|
+
if (bVal == null) return sortBy.direction === "asc" ? 1 : -1;
|
|
186
|
+
const cmp = typeof aVal === "string" && typeof bVal === "string" ? aVal.localeCompare(bVal) : aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
|
|
187
|
+
return sortBy.direction === "asc" ? cmp : -cmp;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return rows;
|
|
191
|
+
},
|
|
192
|
+
// ------------------------------------------------------------------
|
|
193
|
+
// COUNT
|
|
194
|
+
// ------------------------------------------------------------------
|
|
195
|
+
count: async ({ model, where }) => {
|
|
196
|
+
let builder = db.from(model).select();
|
|
197
|
+
if (where) {
|
|
198
|
+
for (const clause of where) {
|
|
199
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const { data: result, error } = await builder;
|
|
203
|
+
if (error) {
|
|
204
|
+
throw new Error(`[AthenaAdapter] count on "${model}" failed: ${error}`);
|
|
205
|
+
}
|
|
206
|
+
return Array.isArray(result) ? result.length : 0;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
213
|
+
0 && (module.exports = {
|
|
214
|
+
athenaAdapter
|
|
215
|
+
});
|
|
216
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\r\n createAdapterFactory,\r\n type AdapterFactory,\r\n type DBAdapterDebugLogOption,\r\n} from \"better-auth/adapters\";\r\nimport type { BetterAuthOptions } from \"better-auth\";\r\nimport { createClient, type SupabaseClient as AthenaClient } from \"@xylex-group/athena\";\r\n\r\n/**\r\n * Configuration options for the Athena adapter.\r\n */\r\nexport interface AthenaAdapterConfig {\r\n /**\r\n * The URL of your Athena gateway.\r\n */\r\n url: string;\r\n /**\r\n * The API key for authenticating with the Athena gateway.\r\n */\r\n apiKey: string;\r\n /**\r\n * The client name sent in requests to the Athena gateway.\r\n */\r\n client?: string;\r\n /**\r\n * Helps you debug issues with the adapter.\r\n */\r\n debugLogs?: DBAdapterDebugLogOption;\r\n /**\r\n * If the table names in the schema are plural.\r\n *\r\n * @default false\r\n */\r\n usePlural?: boolean;\r\n}\r\n\r\ntype AthenaFilterBuilder = {\r\n eq(col: string, val: unknown): AthenaFilterBuilder;\r\n neq(col: string, val: unknown): AthenaFilterBuilder;\r\n gt(col: string, val: unknown): AthenaFilterBuilder;\r\n gte(col: string, val: unknown): AthenaFilterBuilder;\r\n lt(col: string, val: unknown): AthenaFilterBuilder;\r\n lte(col: string, val: unknown): AthenaFilterBuilder;\r\n in(col: string, vals: unknown[]): AthenaFilterBuilder;\r\n not(col: string, op?: string, val?: unknown): AthenaFilterBuilder;\r\n like(col: string, val: string): AthenaFilterBuilder;\r\n};\r\n\r\n/**\r\n * Apply a Better-Auth `CleanedWhere` clause to an Athena filter-chain builder.\r\n */\r\nfunction applyWhere<T extends AthenaFilterBuilder>(\r\n builder: T,\r\n field: string,\r\n operator: string,\r\n value: unknown,\r\n): T {\r\n switch (operator) {\r\n case \"eq\":\r\n return builder.eq(field, value) as T;\r\n case \"ne\":\r\n return builder.neq(field, value) as T;\r\n case \"gt\":\r\n return builder.gt(field, value) as T;\r\n case \"gte\":\r\n return builder.gte(field, value) as T;\r\n case \"lt\":\r\n return builder.lt(field, value) as T;\r\n case \"lte\":\r\n return builder.lte(field, value) as T;\r\n case \"in\":\r\n return builder.in(field, value as unknown[]) as T;\r\n case \"not_in\":\r\n return builder.not(field, \"in\", value) as T;\r\n case \"contains\":\r\n return builder.like(field, `%${value}%`) as T;\r\n case \"starts_with\":\r\n return builder.like(field, `${value}%`) as T;\r\n case \"ends_with\":\r\n return builder.like(field, `%${value}`) as T;\r\n default:\r\n return builder.eq(field, value) as T;\r\n }\r\n}\r\n\r\ntype WhereClause = { field: string; operator: string; value: unknown };\r\n\r\n/**\r\n * Create a Better-Auth database adapter backed by @xylex-group/athena.\r\n *\r\n * Column names are kept in snake_case as required by the Athena gateway.\r\n *\r\n * @example\r\n * ```ts\r\n * import { betterAuth } from \"better-auth\";\r\n * import { athenaAdapter } from \"better-auth-athena\";\r\n *\r\n * export const auth = betterAuth({\r\n * database: athenaAdapter({\r\n * url: process.env.ATHENA_URL!,\r\n * apiKey: process.env.ATHENA_API_KEY!,\r\n * client: \"my-app\",\r\n * }),\r\n * });\r\n * ```\r\n */\r\nexport const athenaAdapter = (config: AthenaAdapterConfig): AdapterFactory<BetterAuthOptions> => {\r\n const db: AthenaClient = createClient(config.url, config.apiKey, {\r\n client: config.client,\r\n });\r\n\r\n return createAdapterFactory({\r\n config: {\r\n adapterId: \"athena\",\r\n adapterName: \"Athena Adapter\",\r\n usePlural: config.usePlural ?? false,\r\n debugLogs: config.debugLogs ?? false,\r\n // Athena/Postgres supports all these natively\r\n supportsJSON: true,\r\n supportsDates: true,\r\n supportsBooleans: true,\r\n supportsNumericIds: true,\r\n },\r\n adapter: () => {\r\n return {\r\n // ------------------------------------------------------------------\r\n // CREATE\r\n // ------------------------------------------------------------------\r\n create: async <T extends Record<string, unknown>>({ model, data }: { model: string; data: T; select?: string[] }) => {\r\n const { data: result, error } = await db\r\n .from(model)\r\n .insert(data)\r\n .select();\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] create on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n // Athena returns the inserted row(s); take the first one.\r\n const row = Array.isArray(result) ? result[0] : result;\r\n return (row ?? data) as T;\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // UPDATE\r\n // ------------------------------------------------------------------\r\n update: async <T>({ model, where, update }: { model: string; where: WhereClause[]; update: T }) => {\r\n let builder = db.from(model).update(update as Record<string, unknown>);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n\r\n const { data: result, error } = await builder.select();\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] update on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n const row = Array.isArray(result) ? result[0] : result;\r\n return (row ?? null) as T | null;\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // UPDATE MANY\r\n // ------------------------------------------------------------------\r\n updateMany: async ({ model, where, update }: { model: string; where: WhereClause[]; update: Record<string, unknown> }) => {\r\n let builder = db.from(model).update(update);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n\r\n const { data: result, error } = await builder.select();\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] updateMany on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n return Array.isArray(result) ? result.length : (result ? 1 : 0);\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // DELETE\r\n // ------------------------------------------------------------------\r\n delete: async ({ model, where }: { model: string; where: WhereClause[] }) => {\r\n let builder = db.from(model);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n\r\n const { error } = await builder.delete();\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] delete on \"${model}\" failed: ${error}`);\r\n }\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // DELETE MANY\r\n // ------------------------------------------------------------------\r\n deleteMany: async ({ model, where }: { model: string; where: WhereClause[] }) => {\r\n let builder = db.from(model);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n\r\n const { data: result, error } = await builder.delete().select();\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] deleteMany on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n return Array.isArray(result) ? result.length : (result ? 1 : 0);\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // FIND ONE\r\n // ------------------------------------------------------------------\r\n findOne: async <T>({ model, where, select }: { model: string; where: WhereClause[]; select?: string[]; join?: unknown }) => {\r\n const columns = select && select.length > 0 ? select.join(\", \") : undefined;\r\n let builder = db.from(model).select(columns);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n\r\n const { data: result, error } = await builder.limit(1);\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] findOne on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n const rows = Array.isArray(result) ? result : (result ? [result] : []);\r\n return (rows[0] ?? null) as T | null;\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // FIND MANY\r\n // ------------------------------------------------------------------\r\n findMany: async <T>({ model, where, limit, sortBy, offset, select }: {\r\n model: string;\r\n where?: WhereClause[];\r\n limit: number;\r\n select?: string[];\r\n sortBy?: { field: string; direction: \"asc\" | \"desc\" };\r\n offset?: number;\r\n join?: unknown;\r\n }) => {\r\n const columns = select && select.length > 0 ? select.join(\", \") : undefined;\r\n let builder = db.from(model).select(columns);\r\n\r\n if (where) {\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n }\r\n\r\n if (limit !== undefined) {\r\n builder = builder.limit(limit);\r\n }\r\n\r\n if (offset !== undefined) {\r\n builder = builder.offset(offset);\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] findMany on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n const rows = (Array.isArray(result) ? result : []) as Record<string, unknown>[];\r\n\r\n // The Athena SDK's select chain does not expose a native orderBy/sort\r\n // method, so we sort the returned rows in memory when sortBy is requested.\r\n if (sortBy) {\r\n rows.sort((a, b) => {\r\n const aVal = a[sortBy.field];\r\n const bVal = b[sortBy.field];\r\n if (aVal == null && bVal == null) return 0;\r\n if (aVal == null) return sortBy.direction === \"asc\" ? -1 : 1;\r\n if (bVal == null) return sortBy.direction === \"asc\" ? 1 : -1;\r\n const cmp =\r\n typeof aVal === \"string\" && typeof bVal === \"string\"\r\n ? aVal.localeCompare(bVal)\r\n : aVal < bVal\r\n ? -1\r\n : aVal > bVal\r\n ? 1\r\n : 0;\r\n return sortBy.direction === \"asc\" ? cmp : -cmp;\r\n });\r\n }\r\n\r\n return rows as T[];\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // COUNT\r\n // ------------------------------------------------------------------\r\n count: async ({ model, where }: { model: string; where?: WhereClause[] }) => {\r\n let builder = db.from(model).select();\r\n\r\n if (where) {\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] count on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n return Array.isArray(result) ? result.length : 0;\r\n },\r\n };\r\n },\r\n });\r\n};\r\n\r\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { DBAdapterDebugLogOption, AdapterFactory } from 'better-auth/adapters';
|
|
2
|
+
import { BetterAuthOptions } from 'better-auth';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Configuration options for the Athena adapter.
|
|
6
|
+
*/
|
|
7
|
+
interface AthenaAdapterConfig {
|
|
8
|
+
/**
|
|
9
|
+
* The URL of your Athena gateway.
|
|
10
|
+
*/
|
|
11
|
+
url: string;
|
|
12
|
+
/**
|
|
13
|
+
* The API key for authenticating with the Athena gateway.
|
|
14
|
+
*/
|
|
15
|
+
apiKey: string;
|
|
16
|
+
/**
|
|
17
|
+
* The client name sent in requests to the Athena gateway.
|
|
18
|
+
*/
|
|
19
|
+
client?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Helps you debug issues with the adapter.
|
|
22
|
+
*/
|
|
23
|
+
debugLogs?: DBAdapterDebugLogOption;
|
|
24
|
+
/**
|
|
25
|
+
* If the table names in the schema are plural.
|
|
26
|
+
*
|
|
27
|
+
* @default false
|
|
28
|
+
*/
|
|
29
|
+
usePlural?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create a Better-Auth database adapter backed by @xylex-group/athena.
|
|
33
|
+
*
|
|
34
|
+
* Column names are kept in snake_case as required by the Athena gateway.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* import { betterAuth } from "better-auth";
|
|
39
|
+
* import { athenaAdapter } from "better-auth-athena";
|
|
40
|
+
*
|
|
41
|
+
* export const auth = betterAuth({
|
|
42
|
+
* database: athenaAdapter({
|
|
43
|
+
* url: process.env.ATHENA_URL!,
|
|
44
|
+
* apiKey: process.env.ATHENA_API_KEY!,
|
|
45
|
+
* client: "my-app",
|
|
46
|
+
* }),
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare const athenaAdapter: (config: AthenaAdapterConfig) => AdapterFactory<BetterAuthOptions>;
|
|
51
|
+
|
|
52
|
+
export { type AthenaAdapterConfig, athenaAdapter };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { DBAdapterDebugLogOption, AdapterFactory } from 'better-auth/adapters';
|
|
2
|
+
import { BetterAuthOptions } from 'better-auth';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Configuration options for the Athena adapter.
|
|
6
|
+
*/
|
|
7
|
+
interface AthenaAdapterConfig {
|
|
8
|
+
/**
|
|
9
|
+
* The URL of your Athena gateway.
|
|
10
|
+
*/
|
|
11
|
+
url: string;
|
|
12
|
+
/**
|
|
13
|
+
* The API key for authenticating with the Athena gateway.
|
|
14
|
+
*/
|
|
15
|
+
apiKey: string;
|
|
16
|
+
/**
|
|
17
|
+
* The client name sent in requests to the Athena gateway.
|
|
18
|
+
*/
|
|
19
|
+
client?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Helps you debug issues with the adapter.
|
|
22
|
+
*/
|
|
23
|
+
debugLogs?: DBAdapterDebugLogOption;
|
|
24
|
+
/**
|
|
25
|
+
* If the table names in the schema are plural.
|
|
26
|
+
*
|
|
27
|
+
* @default false
|
|
28
|
+
*/
|
|
29
|
+
usePlural?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Create a Better-Auth database adapter backed by @xylex-group/athena.
|
|
33
|
+
*
|
|
34
|
+
* Column names are kept in snake_case as required by the Athena gateway.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* import { betterAuth } from "better-auth";
|
|
39
|
+
* import { athenaAdapter } from "better-auth-athena";
|
|
40
|
+
*
|
|
41
|
+
* export const auth = betterAuth({
|
|
42
|
+
* database: athenaAdapter({
|
|
43
|
+
* url: process.env.ATHENA_URL!,
|
|
44
|
+
* apiKey: process.env.ATHENA_API_KEY!,
|
|
45
|
+
* client: "my-app",
|
|
46
|
+
* }),
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare const athenaAdapter: (config: AthenaAdapterConfig) => AdapterFactory<BetterAuthOptions>;
|
|
51
|
+
|
|
52
|
+
export { type AthenaAdapterConfig, athenaAdapter };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
createAdapterFactory
|
|
4
|
+
} from "better-auth/adapters";
|
|
5
|
+
import { createClient } from "@xylex-group/athena";
|
|
6
|
+
function applyWhere(builder, field, operator, value) {
|
|
7
|
+
switch (operator) {
|
|
8
|
+
case "eq":
|
|
9
|
+
return builder.eq(field, value);
|
|
10
|
+
case "ne":
|
|
11
|
+
return builder.neq(field, value);
|
|
12
|
+
case "gt":
|
|
13
|
+
return builder.gt(field, value);
|
|
14
|
+
case "gte":
|
|
15
|
+
return builder.gte(field, value);
|
|
16
|
+
case "lt":
|
|
17
|
+
return builder.lt(field, value);
|
|
18
|
+
case "lte":
|
|
19
|
+
return builder.lte(field, value);
|
|
20
|
+
case "in":
|
|
21
|
+
return builder.in(field, value);
|
|
22
|
+
case "not_in":
|
|
23
|
+
return builder.not(field, "in", value);
|
|
24
|
+
case "contains":
|
|
25
|
+
return builder.like(field, `%${value}%`);
|
|
26
|
+
case "starts_with":
|
|
27
|
+
return builder.like(field, `${value}%`);
|
|
28
|
+
case "ends_with":
|
|
29
|
+
return builder.like(field, `%${value}`);
|
|
30
|
+
default:
|
|
31
|
+
return builder.eq(field, value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
var athenaAdapter = (config) => {
|
|
35
|
+
const db = createClient(config.url, config.apiKey, {
|
|
36
|
+
client: config.client
|
|
37
|
+
});
|
|
38
|
+
return createAdapterFactory({
|
|
39
|
+
config: {
|
|
40
|
+
adapterId: "athena",
|
|
41
|
+
adapterName: "Athena Adapter",
|
|
42
|
+
usePlural: config.usePlural ?? false,
|
|
43
|
+
debugLogs: config.debugLogs ?? false,
|
|
44
|
+
// Athena/Postgres supports all these natively
|
|
45
|
+
supportsJSON: true,
|
|
46
|
+
supportsDates: true,
|
|
47
|
+
supportsBooleans: true,
|
|
48
|
+
supportsNumericIds: true
|
|
49
|
+
},
|
|
50
|
+
adapter: () => {
|
|
51
|
+
return {
|
|
52
|
+
// ------------------------------------------------------------------
|
|
53
|
+
// CREATE
|
|
54
|
+
// ------------------------------------------------------------------
|
|
55
|
+
create: async ({ model, data }) => {
|
|
56
|
+
const { data: result, error } = await db.from(model).insert(data).select();
|
|
57
|
+
if (error) {
|
|
58
|
+
throw new Error(`[AthenaAdapter] create on "${model}" failed: ${error}`);
|
|
59
|
+
}
|
|
60
|
+
const row = Array.isArray(result) ? result[0] : result;
|
|
61
|
+
return row ?? data;
|
|
62
|
+
},
|
|
63
|
+
// ------------------------------------------------------------------
|
|
64
|
+
// UPDATE
|
|
65
|
+
// ------------------------------------------------------------------
|
|
66
|
+
update: async ({ model, where, update }) => {
|
|
67
|
+
let builder = db.from(model).update(update);
|
|
68
|
+
for (const clause of where) {
|
|
69
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
70
|
+
}
|
|
71
|
+
const { data: result, error } = await builder.select();
|
|
72
|
+
if (error) {
|
|
73
|
+
throw new Error(`[AthenaAdapter] update on "${model}" failed: ${error}`);
|
|
74
|
+
}
|
|
75
|
+
const row = Array.isArray(result) ? result[0] : result;
|
|
76
|
+
return row ?? null;
|
|
77
|
+
},
|
|
78
|
+
// ------------------------------------------------------------------
|
|
79
|
+
// UPDATE MANY
|
|
80
|
+
// ------------------------------------------------------------------
|
|
81
|
+
updateMany: async ({ model, where, update }) => {
|
|
82
|
+
let builder = db.from(model).update(update);
|
|
83
|
+
for (const clause of where) {
|
|
84
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
85
|
+
}
|
|
86
|
+
const { data: result, error } = await builder.select();
|
|
87
|
+
if (error) {
|
|
88
|
+
throw new Error(`[AthenaAdapter] updateMany on "${model}" failed: ${error}`);
|
|
89
|
+
}
|
|
90
|
+
return Array.isArray(result) ? result.length : result ? 1 : 0;
|
|
91
|
+
},
|
|
92
|
+
// ------------------------------------------------------------------
|
|
93
|
+
// DELETE
|
|
94
|
+
// ------------------------------------------------------------------
|
|
95
|
+
delete: async ({ model, where }) => {
|
|
96
|
+
let builder = db.from(model);
|
|
97
|
+
for (const clause of where) {
|
|
98
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
99
|
+
}
|
|
100
|
+
const { error } = await builder.delete();
|
|
101
|
+
if (error) {
|
|
102
|
+
throw new Error(`[AthenaAdapter] delete on "${model}" failed: ${error}`);
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
// ------------------------------------------------------------------
|
|
106
|
+
// DELETE MANY
|
|
107
|
+
// ------------------------------------------------------------------
|
|
108
|
+
deleteMany: async ({ model, where }) => {
|
|
109
|
+
let builder = db.from(model);
|
|
110
|
+
for (const clause of where) {
|
|
111
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
112
|
+
}
|
|
113
|
+
const { data: result, error } = await builder.delete().select();
|
|
114
|
+
if (error) {
|
|
115
|
+
throw new Error(`[AthenaAdapter] deleteMany on "${model}" failed: ${error}`);
|
|
116
|
+
}
|
|
117
|
+
return Array.isArray(result) ? result.length : result ? 1 : 0;
|
|
118
|
+
},
|
|
119
|
+
// ------------------------------------------------------------------
|
|
120
|
+
// FIND ONE
|
|
121
|
+
// ------------------------------------------------------------------
|
|
122
|
+
findOne: async ({ model, where, select }) => {
|
|
123
|
+
const columns = select && select.length > 0 ? select.join(", ") : void 0;
|
|
124
|
+
let builder = db.from(model).select(columns);
|
|
125
|
+
for (const clause of where) {
|
|
126
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
127
|
+
}
|
|
128
|
+
const { data: result, error } = await builder.limit(1);
|
|
129
|
+
if (error) {
|
|
130
|
+
throw new Error(`[AthenaAdapter] findOne on "${model}" failed: ${error}`);
|
|
131
|
+
}
|
|
132
|
+
const rows = Array.isArray(result) ? result : result ? [result] : [];
|
|
133
|
+
return rows[0] ?? null;
|
|
134
|
+
},
|
|
135
|
+
// ------------------------------------------------------------------
|
|
136
|
+
// FIND MANY
|
|
137
|
+
// ------------------------------------------------------------------
|
|
138
|
+
findMany: async ({ model, where, limit, sortBy, offset, select }) => {
|
|
139
|
+
const columns = select && select.length > 0 ? select.join(", ") : void 0;
|
|
140
|
+
let builder = db.from(model).select(columns);
|
|
141
|
+
if (where) {
|
|
142
|
+
for (const clause of where) {
|
|
143
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (limit !== void 0) {
|
|
147
|
+
builder = builder.limit(limit);
|
|
148
|
+
}
|
|
149
|
+
if (offset !== void 0) {
|
|
150
|
+
builder = builder.offset(offset);
|
|
151
|
+
}
|
|
152
|
+
const { data: result, error } = await builder;
|
|
153
|
+
if (error) {
|
|
154
|
+
throw new Error(`[AthenaAdapter] findMany on "${model}" failed: ${error}`);
|
|
155
|
+
}
|
|
156
|
+
const rows = Array.isArray(result) ? result : [];
|
|
157
|
+
if (sortBy) {
|
|
158
|
+
rows.sort((a, b) => {
|
|
159
|
+
const aVal = a[sortBy.field];
|
|
160
|
+
const bVal = b[sortBy.field];
|
|
161
|
+
if (aVal == null && bVal == null) return 0;
|
|
162
|
+
if (aVal == null) return sortBy.direction === "asc" ? -1 : 1;
|
|
163
|
+
if (bVal == null) return sortBy.direction === "asc" ? 1 : -1;
|
|
164
|
+
const cmp = typeof aVal === "string" && typeof bVal === "string" ? aVal.localeCompare(bVal) : aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
|
|
165
|
+
return sortBy.direction === "asc" ? cmp : -cmp;
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return rows;
|
|
169
|
+
},
|
|
170
|
+
// ------------------------------------------------------------------
|
|
171
|
+
// COUNT
|
|
172
|
+
// ------------------------------------------------------------------
|
|
173
|
+
count: async ({ model, where }) => {
|
|
174
|
+
let builder = db.from(model).select();
|
|
175
|
+
if (where) {
|
|
176
|
+
for (const clause of where) {
|
|
177
|
+
builder = applyWhere(builder, clause.field, clause.operator, clause.value);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const { data: result, error } = await builder;
|
|
181
|
+
if (error) {
|
|
182
|
+
throw new Error(`[AthenaAdapter] count on "${model}" failed: ${error}`);
|
|
183
|
+
}
|
|
184
|
+
return Array.isArray(result) ? result.length : 0;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
};
|
|
190
|
+
export {
|
|
191
|
+
athenaAdapter
|
|
192
|
+
};
|
|
193
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\r\n createAdapterFactory,\r\n type AdapterFactory,\r\n type DBAdapterDebugLogOption,\r\n} from \"better-auth/adapters\";\r\nimport type { BetterAuthOptions } from \"better-auth\";\r\nimport { createClient, type SupabaseClient as AthenaClient } from \"@xylex-group/athena\";\r\n\r\n/**\r\n * Configuration options for the Athena adapter.\r\n */\r\nexport interface AthenaAdapterConfig {\r\n /**\r\n * The URL of your Athena gateway.\r\n */\r\n url: string;\r\n /**\r\n * The API key for authenticating with the Athena gateway.\r\n */\r\n apiKey: string;\r\n /**\r\n * The client name sent in requests to the Athena gateway.\r\n */\r\n client?: string;\r\n /**\r\n * Helps you debug issues with the adapter.\r\n */\r\n debugLogs?: DBAdapterDebugLogOption;\r\n /**\r\n * If the table names in the schema are plural.\r\n *\r\n * @default false\r\n */\r\n usePlural?: boolean;\r\n}\r\n\r\ntype AthenaFilterBuilder = {\r\n eq(col: string, val: unknown): AthenaFilterBuilder;\r\n neq(col: string, val: unknown): AthenaFilterBuilder;\r\n gt(col: string, val: unknown): AthenaFilterBuilder;\r\n gte(col: string, val: unknown): AthenaFilterBuilder;\r\n lt(col: string, val: unknown): AthenaFilterBuilder;\r\n lte(col: string, val: unknown): AthenaFilterBuilder;\r\n in(col: string, vals: unknown[]): AthenaFilterBuilder;\r\n not(col: string, op?: string, val?: unknown): AthenaFilterBuilder;\r\n like(col: string, val: string): AthenaFilterBuilder;\r\n};\r\n\r\n/**\r\n * Apply a Better-Auth `CleanedWhere` clause to an Athena filter-chain builder.\r\n */\r\nfunction applyWhere<T extends AthenaFilterBuilder>(\r\n builder: T,\r\n field: string,\r\n operator: string,\r\n value: unknown,\r\n): T {\r\n switch (operator) {\r\n case \"eq\":\r\n return builder.eq(field, value) as T;\r\n case \"ne\":\r\n return builder.neq(field, value) as T;\r\n case \"gt\":\r\n return builder.gt(field, value) as T;\r\n case \"gte\":\r\n return builder.gte(field, value) as T;\r\n case \"lt\":\r\n return builder.lt(field, value) as T;\r\n case \"lte\":\r\n return builder.lte(field, value) as T;\r\n case \"in\":\r\n return builder.in(field, value as unknown[]) as T;\r\n case \"not_in\":\r\n return builder.not(field, \"in\", value) as T;\r\n case \"contains\":\r\n return builder.like(field, `%${value}%`) as T;\r\n case \"starts_with\":\r\n return builder.like(field, `${value}%`) as T;\r\n case \"ends_with\":\r\n return builder.like(field, `%${value}`) as T;\r\n default:\r\n return builder.eq(field, value) as T;\r\n }\r\n}\r\n\r\ntype WhereClause = { field: string; operator: string; value: unknown };\r\n\r\n/**\r\n * Create a Better-Auth database adapter backed by @xylex-group/athena.\r\n *\r\n * Column names are kept in snake_case as required by the Athena gateway.\r\n *\r\n * @example\r\n * ```ts\r\n * import { betterAuth } from \"better-auth\";\r\n * import { athenaAdapter } from \"better-auth-athena\";\r\n *\r\n * export const auth = betterAuth({\r\n * database: athenaAdapter({\r\n * url: process.env.ATHENA_URL!,\r\n * apiKey: process.env.ATHENA_API_KEY!,\r\n * client: \"my-app\",\r\n * }),\r\n * });\r\n * ```\r\n */\r\nexport const athenaAdapter = (config: AthenaAdapterConfig): AdapterFactory<BetterAuthOptions> => {\r\n const db: AthenaClient = createClient(config.url, config.apiKey, {\r\n client: config.client,\r\n });\r\n\r\n return createAdapterFactory({\r\n config: {\r\n adapterId: \"athena\",\r\n adapterName: \"Athena Adapter\",\r\n usePlural: config.usePlural ?? false,\r\n debugLogs: config.debugLogs ?? false,\r\n // Athena/Postgres supports all these natively\r\n supportsJSON: true,\r\n supportsDates: true,\r\n supportsBooleans: true,\r\n supportsNumericIds: true,\r\n },\r\n adapter: () => {\r\n return {\r\n // ------------------------------------------------------------------\r\n // CREATE\r\n // ------------------------------------------------------------------\r\n create: async <T extends Record<string, unknown>>({ model, data }: { model: string; data: T; select?: string[] }) => {\r\n const { data: result, error } = await db\r\n .from(model)\r\n .insert(data)\r\n .select();\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] create on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n // Athena returns the inserted row(s); take the first one.\r\n const row = Array.isArray(result) ? result[0] : result;\r\n return (row ?? data) as T;\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // UPDATE\r\n // ------------------------------------------------------------------\r\n update: async <T>({ model, where, update }: { model: string; where: WhereClause[]; update: T }) => {\r\n let builder = db.from(model).update(update as Record<string, unknown>);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n\r\n const { data: result, error } = await builder.select();\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] update on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n const row = Array.isArray(result) ? result[0] : result;\r\n return (row ?? null) as T | null;\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // UPDATE MANY\r\n // ------------------------------------------------------------------\r\n updateMany: async ({ model, where, update }: { model: string; where: WhereClause[]; update: Record<string, unknown> }) => {\r\n let builder = db.from(model).update(update);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n\r\n const { data: result, error } = await builder.select();\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] updateMany on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n return Array.isArray(result) ? result.length : (result ? 1 : 0);\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // DELETE\r\n // ------------------------------------------------------------------\r\n delete: async ({ model, where }: { model: string; where: WhereClause[] }) => {\r\n let builder = db.from(model);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n\r\n const { error } = await builder.delete();\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] delete on \"${model}\" failed: ${error}`);\r\n }\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // DELETE MANY\r\n // ------------------------------------------------------------------\r\n deleteMany: async ({ model, where }: { model: string; where: WhereClause[] }) => {\r\n let builder = db.from(model);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n\r\n const { data: result, error } = await builder.delete().select();\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] deleteMany on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n return Array.isArray(result) ? result.length : (result ? 1 : 0);\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // FIND ONE\r\n // ------------------------------------------------------------------\r\n findOne: async <T>({ model, where, select }: { model: string; where: WhereClause[]; select?: string[]; join?: unknown }) => {\r\n const columns = select && select.length > 0 ? select.join(\", \") : undefined;\r\n let builder = db.from(model).select(columns);\r\n\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n\r\n const { data: result, error } = await builder.limit(1);\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] findOne on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n const rows = Array.isArray(result) ? result : (result ? [result] : []);\r\n return (rows[0] ?? null) as T | null;\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // FIND MANY\r\n // ------------------------------------------------------------------\r\n findMany: async <T>({ model, where, limit, sortBy, offset, select }: {\r\n model: string;\r\n where?: WhereClause[];\r\n limit: number;\r\n select?: string[];\r\n sortBy?: { field: string; direction: \"asc\" | \"desc\" };\r\n offset?: number;\r\n join?: unknown;\r\n }) => {\r\n const columns = select && select.length > 0 ? select.join(\", \") : undefined;\r\n let builder = db.from(model).select(columns);\r\n\r\n if (where) {\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n }\r\n\r\n if (limit !== undefined) {\r\n builder = builder.limit(limit);\r\n }\r\n\r\n if (offset !== undefined) {\r\n builder = builder.offset(offset);\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] findMany on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n const rows = (Array.isArray(result) ? result : []) as Record<string, unknown>[];\r\n\r\n // The Athena SDK's select chain does not expose a native orderBy/sort\r\n // method, so we sort the returned rows in memory when sortBy is requested.\r\n if (sortBy) {\r\n rows.sort((a, b) => {\r\n const aVal = a[sortBy.field];\r\n const bVal = b[sortBy.field];\r\n if (aVal == null && bVal == null) return 0;\r\n if (aVal == null) return sortBy.direction === \"asc\" ? -1 : 1;\r\n if (bVal == null) return sortBy.direction === \"asc\" ? 1 : -1;\r\n const cmp =\r\n typeof aVal === \"string\" && typeof bVal === \"string\"\r\n ? aVal.localeCompare(bVal)\r\n : aVal < bVal\r\n ? -1\r\n : aVal > bVal\r\n ? 1\r\n : 0;\r\n return sortBy.direction === \"asc\" ? cmp : -cmp;\r\n });\r\n }\r\n\r\n return rows as T[];\r\n },\r\n\r\n // ------------------------------------------------------------------\r\n // COUNT\r\n // ------------------------------------------------------------------\r\n count: async ({ model, where }: { model: string; where?: WhereClause[] }) => {\r\n let builder = db.from(model).select();\r\n\r\n if (where) {\r\n for (const clause of where) {\r\n builder = applyWhere(builder, clause.field, clause.operator, clause.value);\r\n }\r\n }\r\n\r\n const { data: result, error } = await builder;\r\n\r\n if (error) {\r\n throw new Error(`[AthenaAdapter] count on \"${model}\" failed: ${error}`);\r\n }\r\n\r\n return Array.isArray(result) ? result.length : 0;\r\n },\r\n };\r\n },\r\n });\r\n};\r\n\r\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xylex-group/better-auth-athena",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A better-Auth database adapter for @xylex-group/athena",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"CONTRIBUTING.md",
|
|
20
|
+
"CONTRIBUTORS.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup",
|
|
24
|
+
"dev": "tsup --watch",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest",
|
|
28
|
+
"prepublishOnly": "npm run build && npm run typecheck && npm run test"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/xylex-group/better-auth-athena.git"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"better-auth",
|
|
36
|
+
"athena",
|
|
37
|
+
"database",
|
|
38
|
+
"adapter"
|
|
39
|
+
],
|
|
40
|
+
"author": "XYLEX GROUP",
|
|
41
|
+
"contributors": [
|
|
42
|
+
"floris-xlx"
|
|
43
|
+
],
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"type": "module",
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=20.19.0"
|
|
48
|
+
},
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/xylex-group/better-auth-athena/issues"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://github.com/xylex-group/better-auth-athena#readme",
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@xylex-group/athena": "^1.1.1",
|
|
55
|
+
"better-auth": "^1.5.5"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/node": "^25.5.0",
|
|
59
|
+
"@xylex-group/athena": "^1.1.1",
|
|
60
|
+
"better-auth": "^1.5.5",
|
|
61
|
+
"tsup": "^8.5.1",
|
|
62
|
+
"typescript": "^5.9.3",
|
|
63
|
+
"vitest": "^4.1.0"
|
|
64
|
+
}
|
|
65
|
+
}
|