better-auth-instantdb 1.3.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/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/adapter/create-schema.d.ts +9 -0
- package/dist/adapter/create-schema.js +178 -0
- package/dist/adapter/instant-adapter.d.ts +25 -0
- package/dist/adapter/instant-adapter.js +273 -0
- package/dist/client-plugin.d.ts +2143 -0
- package/dist/client-plugin.js +21 -0
- package/dist/create-schema.d.ts +25 -0
- package/dist/create-schema.js +115 -0
- package/dist/create-schema.js.map +1 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +160 -0
- package/dist/instant-adapter.d.ts +26 -0
- package/dist/instant-adapter.js +214 -0
- package/dist/instant-adapter.js.map +1 -0
- package/dist/instant-auth.d.ts +3 -0
- package/dist/instant-auth.js +9 -0
- package/dist/lib/instant-auth.d.ts +3 -0
- package/dist/lib/instant-auth.js +9 -0
- package/dist/lib/utils.d.ts +12 -0
- package/dist/lib/utils.js +22 -0
- package/dist/metafile-cjs.json +1 -0
- package/dist/metafile-esm.json +1 -0
- package/dist/react/client-plugin.d.ts +2143 -0
- package/dist/react/client-plugin.js +21 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.js +4 -0
- package/dist/react/instant-auth.d.ts +7 -0
- package/dist/react/instant-auth.js +5 -0
- package/dist/react/react.d.ts +2 -0
- package/dist/react/react.js +2 -0
- package/dist/react/types.d.ts +6 -0
- package/dist/react/types.js +1 -0
- package/dist/react/use-hydrated.d.ts +1 -0
- package/dist/react/use-hydrated.js +7 -0
- package/dist/react/use-instant-auth.d.ts +8 -0
- package/dist/react/use-instant-auth.js +13 -0
- package/dist/react/use-instant-session.d.ts +32 -0
- package/dist/react/use-instant-session.js +25 -0
- package/dist/react/use-persistent-session.d.ts +27 -0
- package/dist/react/use-persistent-session.js +49 -0
- package/dist/react/use-session.d.ts +0 -0
- package/dist/react/use-session.js +1 -0
- package/dist/react/with-instant.d.ts +3 -0
- package/dist/react/with-instant.js +47 -0
- package/dist/react.d.ts +2 -0
- package/dist/react.js +2 -0
- package/dist/shared/instant-auth.d.ts +4 -0
- package/dist/shared/instant-auth.js +9 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.js +9 -0
- package/package.json +70 -0
- package/src/adapter/create-schema.ts +232 -0
- package/src/adapter/instant-adapter.ts +422 -0
- package/src/index.ts +2 -0
- package/src/lib/utils.ts +24 -0
- package/src/react/index.ts +4 -0
- package/src/react/instant-auth.tsx +17 -0
- package/src/react/types.ts +9 -0
- package/src/react/use-hydrated.ts +13 -0
- package/src/react/use-instant-auth.ts +28 -0
- package/src/react/use-instant-session.ts +46 -0
- package/src/react/use-persistent-session.ts +64 -0
- package/src/shared/instant-auth.ts +18 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const instantDBPluginClient = ({ authClient }) => {
|
|
2
|
+
// Store the original useSession hook
|
|
3
|
+
const originalUseSession = authClient.useSession;
|
|
4
|
+
// Override useSession with custom implementation using Object.defineProperty
|
|
5
|
+
// This ensures it works even if useSession is a getter or non-writable property
|
|
6
|
+
Object.defineProperty(authClient, "useSession", {
|
|
7
|
+
value: () => {
|
|
8
|
+
// Call the original hook to get session data
|
|
9
|
+
const sessionResult = originalUseSession.call(authClient);
|
|
10
|
+
// You can add custom logic here
|
|
11
|
+
// For example, sync with InstantDB, transform data, etc.
|
|
12
|
+
console.log("useSession override called!", sessionResult);
|
|
13
|
+
// Return the session result (or modified version)
|
|
14
|
+
return sessionResult;
|
|
15
|
+
},
|
|
16
|
+
writable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
enumerable: true
|
|
19
|
+
});
|
|
20
|
+
return authClient;
|
|
21
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DBAdapterSchemaCreation } from "better-auth/adapters";
|
|
2
|
+
type BetterAuthField = {
|
|
3
|
+
type: string | string[];
|
|
4
|
+
required?: boolean;
|
|
5
|
+
unique?: boolean;
|
|
6
|
+
defaultValue?: unknown;
|
|
7
|
+
input?: boolean;
|
|
8
|
+
sortable?: boolean;
|
|
9
|
+
fieldName?: string;
|
|
10
|
+
references?: {
|
|
11
|
+
model: string;
|
|
12
|
+
field: string;
|
|
13
|
+
onDelete?: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
type BetterAuthTable = {
|
|
17
|
+
modelName: string;
|
|
18
|
+
fields: Record<string, BetterAuthField>;
|
|
19
|
+
order?: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Creates an InstantDB schema file from Better Auth schema format
|
|
23
|
+
*/
|
|
24
|
+
export declare function createSchema(file: string, tables: Record<string, BetterAuthTable>, usePlural: boolean): DBAdapterSchemaCreation;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a Better Auth field type to InstantDB field type
|
|
3
|
+
*/
|
|
4
|
+
function convertFieldType(field) {
|
|
5
|
+
const { type, required, unique, sortable } = field;
|
|
6
|
+
// Handle type as string or array
|
|
7
|
+
const typeStr = Array.isArray(type) ? type[0] : type;
|
|
8
|
+
let fieldType = "";
|
|
9
|
+
switch (typeStr) {
|
|
10
|
+
case "string":
|
|
11
|
+
fieldType = "i.string()";
|
|
12
|
+
break;
|
|
13
|
+
case "boolean":
|
|
14
|
+
fieldType = "i.boolean()";
|
|
15
|
+
break;
|
|
16
|
+
case "date":
|
|
17
|
+
fieldType = "i.date()";
|
|
18
|
+
break;
|
|
19
|
+
case "number":
|
|
20
|
+
fieldType = "i.number()";
|
|
21
|
+
break;
|
|
22
|
+
default:
|
|
23
|
+
fieldType = "i.string()"; // Default to string for unknown types
|
|
24
|
+
}
|
|
25
|
+
// Apply modifiers
|
|
26
|
+
if (unique) {
|
|
27
|
+
fieldType += ".unique()";
|
|
28
|
+
}
|
|
29
|
+
// Only make optional if required is explicitly false
|
|
30
|
+
// If required is true, never make it optional (even if defaultValue exists)
|
|
31
|
+
if (required === false) {
|
|
32
|
+
fieldType += ".optional()";
|
|
33
|
+
}
|
|
34
|
+
// Add indexed if sortable
|
|
35
|
+
if (sortable) {
|
|
36
|
+
fieldType += ".indexed()";
|
|
37
|
+
}
|
|
38
|
+
return fieldType;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Converts Better Auth schema format to InstantDB schema format
|
|
42
|
+
*/
|
|
43
|
+
function convertToInstantDBSchema(tables, usePlural) {
|
|
44
|
+
const entities = {};
|
|
45
|
+
for (const [key, table] of Object.entries(tables)) {
|
|
46
|
+
const { modelName, fields } = table;
|
|
47
|
+
// Special handling for user table
|
|
48
|
+
if (modelName === "user") {
|
|
49
|
+
const userFields = [];
|
|
50
|
+
const processedFields = new Set();
|
|
51
|
+
// Always add email, imageURL, and type at the top (exact format required)
|
|
52
|
+
userFields.push("email: i.string().unique().indexed().optional()");
|
|
53
|
+
processedFields.add("email");
|
|
54
|
+
userFields.push("imageURL: i.string().optional()");
|
|
55
|
+
processedFields.add("imageURL"); // Skip imageURL if it exists in fields
|
|
56
|
+
userFields.push("type: i.string().optional()");
|
|
57
|
+
processedFields.add("type"); // Skip type if it exists in fields
|
|
58
|
+
// Add all other fields from the schema (including image as-is, don't transform it)
|
|
59
|
+
// All Better Auth fields must be optional on $users
|
|
60
|
+
for (const [fieldKey, field] of Object.entries(fields)) {
|
|
61
|
+
// Skip fields that are always included at the top: email, imageURL, type
|
|
62
|
+
if (processedFields.has(fieldKey)) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
// Add field as-is but force it to be optional
|
|
66
|
+
const fieldType = convertFieldType(field);
|
|
67
|
+
// Ensure it ends with .optional() - remove existing .optional() if present and add it
|
|
68
|
+
const optionalFieldType = fieldType.endsWith(".optional()")
|
|
69
|
+
? fieldType
|
|
70
|
+
: `${fieldType}.optional()`;
|
|
71
|
+
userFields.push(`${fieldKey}: ${optionalFieldType}`);
|
|
72
|
+
}
|
|
73
|
+
entities.$users = `i.entity({\n ${userFields.join(",\n ")}\n })`;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// For other tables, use the key as entity name
|
|
77
|
+
const entityFields = [];
|
|
78
|
+
for (const [fieldKey, field] of Object.entries(fields)) {
|
|
79
|
+
const fieldType = convertFieldType(field);
|
|
80
|
+
entityFields.push(`${fieldKey}: ${fieldType}`);
|
|
81
|
+
}
|
|
82
|
+
// Pluralize table name if usePlural is true
|
|
83
|
+
const entityName = usePlural ? `${key}s` : key;
|
|
84
|
+
entities[entityName] =
|
|
85
|
+
`i.entity({\n ${entityFields.join(",\n ")}\n })`;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Generate the schema file content
|
|
89
|
+
const entitiesString = Object.entries(entities)
|
|
90
|
+
.map(([name, definition]) => ` ${name}: ${definition}`)
|
|
91
|
+
.join(",\n");
|
|
92
|
+
return `// Docs: https://www.instantdb.com/docs/modeling-data
|
|
93
|
+
|
|
94
|
+
import { i } from "@instantdb/react"
|
|
95
|
+
|
|
96
|
+
export const authSchema = i.schema({
|
|
97
|
+
entities: {
|
|
98
|
+
${entitiesString}
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
`;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Creates an InstantDB schema file from Better Auth schema format
|
|
105
|
+
*/
|
|
106
|
+
export function createSchema(file, tables, usePlural) {
|
|
107
|
+
const schemaContent = convertToInstantDBSchema(tables, usePlural);
|
|
108
|
+
// const filePath = resolve(process.cwd(), file)
|
|
109
|
+
// writeFileSync(file, schemaContent, "utf-8")
|
|
110
|
+
//console.log(`Schema file created at: ${filePath}`)
|
|
111
|
+
return {
|
|
112
|
+
code: schemaContent,
|
|
113
|
+
path: file
|
|
114
|
+
};
|
|
115
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-schema.js","sourceRoot":"","sources":["../src/create-schema.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as better_auth_adapters from 'better-auth/adapters';
|
|
2
|
+
import { DBAdapterDebugLogOption } from 'better-auth/adapters';
|
|
3
|
+
import { InstantAdminDatabase } from '@instantdb/admin';
|
|
4
|
+
|
|
5
|
+
interface InstantAdapterConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Helps you debug issues with the adapter.
|
|
8
|
+
*/
|
|
9
|
+
debugLogs?: DBAdapterDebugLogOption;
|
|
10
|
+
/**
|
|
11
|
+
* If the table names in the schema are plural.
|
|
12
|
+
*/
|
|
13
|
+
usePlural?: boolean;
|
|
14
|
+
db: InstantAdminDatabase<any>;
|
|
15
|
+
}
|
|
16
|
+
declare const instantAdapter: (config: InstantAdapterConfig) => better_auth_adapters.AdapterFactory;
|
|
17
|
+
|
|
18
|
+
export { instantAdapter };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAiC"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { createAdapterFactory } from 'better-auth/adapters';
|
|
2
|
+
|
|
3
|
+
// src/instant-adapter.ts
|
|
4
|
+
|
|
5
|
+
// src/create-schema.ts
|
|
6
|
+
function convertFieldType(field) {
|
|
7
|
+
const { type, required, unique, defaultValue, sortable } = field;
|
|
8
|
+
const typeStr = Array.isArray(type) ? type[0] : type;
|
|
9
|
+
let fieldType = "";
|
|
10
|
+
switch (typeStr) {
|
|
11
|
+
case "string":
|
|
12
|
+
fieldType = "i.string()";
|
|
13
|
+
break;
|
|
14
|
+
case "boolean":
|
|
15
|
+
fieldType = "i.boolean()";
|
|
16
|
+
break;
|
|
17
|
+
case "date":
|
|
18
|
+
fieldType = "i.date()";
|
|
19
|
+
break;
|
|
20
|
+
case "number":
|
|
21
|
+
fieldType = "i.number()";
|
|
22
|
+
break;
|
|
23
|
+
default:
|
|
24
|
+
fieldType = "i.string()";
|
|
25
|
+
}
|
|
26
|
+
if (unique) {
|
|
27
|
+
fieldType += ".unique()";
|
|
28
|
+
}
|
|
29
|
+
if (required === false) {
|
|
30
|
+
fieldType += ".optional()";
|
|
31
|
+
}
|
|
32
|
+
if (sortable) {
|
|
33
|
+
fieldType += ".indexed()";
|
|
34
|
+
}
|
|
35
|
+
return fieldType;
|
|
36
|
+
}
|
|
37
|
+
function convertToInstantDBSchema(tables, usePlural) {
|
|
38
|
+
const entities = {};
|
|
39
|
+
for (const [key, table] of Object.entries(tables)) {
|
|
40
|
+
const { modelName, fields } = table;
|
|
41
|
+
if (modelName === "user") {
|
|
42
|
+
const userFields = [];
|
|
43
|
+
const processedFields = /* @__PURE__ */ new Set();
|
|
44
|
+
userFields.push("email: i.string().unique().indexed()");
|
|
45
|
+
processedFields.add("email");
|
|
46
|
+
userFields.push("imageURL: i.string().optional()");
|
|
47
|
+
processedFields.add("imageURL");
|
|
48
|
+
userFields.push("type: i.string().optional()");
|
|
49
|
+
processedFields.add("type");
|
|
50
|
+
for (const [fieldKey, field] of Object.entries(fields)) {
|
|
51
|
+
if (processedFields.has(fieldKey)) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const fieldType = convertFieldType(field);
|
|
55
|
+
const optionalFieldType = fieldType.endsWith(".optional()") ? fieldType : `${fieldType}.optional()`;
|
|
56
|
+
userFields.push(`${fieldKey}: ${optionalFieldType}`);
|
|
57
|
+
}
|
|
58
|
+
entities["$users"] = `i.entity({
|
|
59
|
+
${userFields.join(",\n ")}
|
|
60
|
+
})`;
|
|
61
|
+
} else {
|
|
62
|
+
const entityFields = [];
|
|
63
|
+
for (const [fieldKey, field] of Object.entries(fields)) {
|
|
64
|
+
const fieldType = convertFieldType(field);
|
|
65
|
+
entityFields.push(`${fieldKey}: ${fieldType}`);
|
|
66
|
+
}
|
|
67
|
+
const entityName = usePlural ? `${key}s` : key;
|
|
68
|
+
entities[entityName] = `i.entity({
|
|
69
|
+
${entityFields.join(",\n ")}
|
|
70
|
+
})`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const entitiesString = Object.entries(entities).map(([name, definition]) => ` ${name}: ${definition}`).join(",\n");
|
|
74
|
+
return `// Docs: https://www.instantdb.com/docs/modeling-data
|
|
75
|
+
|
|
76
|
+
import { i } from "@instantdb/react"
|
|
77
|
+
|
|
78
|
+
export const authSchema = i.schema({
|
|
79
|
+
entities: {
|
|
80
|
+
${entitiesString}
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
`;
|
|
84
|
+
}
|
|
85
|
+
function createSchema(file, tables, usePlural = false) {
|
|
86
|
+
const schemaContent = convertToInstantDBSchema(tables, usePlural);
|
|
87
|
+
return {
|
|
88
|
+
code: schemaContent,
|
|
89
|
+
path: file
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/instant-adapter.ts
|
|
94
|
+
var instantAdapter = (config) => {
|
|
95
|
+
var _a, _b;
|
|
96
|
+
const usePlural = (_a = config.usePlural) != null ? _a : false;
|
|
97
|
+
return createAdapterFactory({
|
|
98
|
+
config: {
|
|
99
|
+
adapterId: "instantdb-adapter",
|
|
100
|
+
// A unique identifier for the adapter.
|
|
101
|
+
adapterName: "InstantDB Adapter",
|
|
102
|
+
// The name of the adapter.
|
|
103
|
+
usePlural,
|
|
104
|
+
// Whether the table names in the schema are plural.
|
|
105
|
+
debugLogs: (_b = config.debugLogs) != null ? _b : false,
|
|
106
|
+
// Whether to enable debug logs.
|
|
107
|
+
supportsJSON: true,
|
|
108
|
+
// Whether the database supports JSON. (Default: false)
|
|
109
|
+
supportsDates: true,
|
|
110
|
+
// Whether the database supports dates. (Default: true)
|
|
111
|
+
supportsBooleans: true,
|
|
112
|
+
// Whether the database supports booleans. (Default: true)
|
|
113
|
+
supportsNumericIds: false
|
|
114
|
+
// Whether the database supports auto-incrementing numeric IDs. (Default: true)
|
|
115
|
+
},
|
|
116
|
+
adapter: ({
|
|
117
|
+
options,
|
|
118
|
+
schema,
|
|
119
|
+
debugLog,
|
|
120
|
+
getDefaultModelName,
|
|
121
|
+
getDefaultFieldName
|
|
122
|
+
}) => {
|
|
123
|
+
return {
|
|
124
|
+
create: async ({ data, model, select }) => {
|
|
125
|
+
if (getDefaultModelName(model) === "user") {
|
|
126
|
+
console.log("create user", data);
|
|
127
|
+
}
|
|
128
|
+
throw new Error("Not implemented");
|
|
129
|
+
},
|
|
130
|
+
update: async ({ update, model, where }) => {
|
|
131
|
+
return null;
|
|
132
|
+
},
|
|
133
|
+
updateMany: async ({ update, model, where }) => {
|
|
134
|
+
return 0;
|
|
135
|
+
},
|
|
136
|
+
delete: async ({ model, where }) => {
|
|
137
|
+
return;
|
|
138
|
+
},
|
|
139
|
+
deleteMany: async ({ model, where }) => {
|
|
140
|
+
return 0;
|
|
141
|
+
},
|
|
142
|
+
findOne: async ({ model, where, select }) => {
|
|
143
|
+
return null;
|
|
144
|
+
},
|
|
145
|
+
findMany: async ({ model, where, limit, sortBy, offset }) => {
|
|
146
|
+
return [];
|
|
147
|
+
},
|
|
148
|
+
count: async ({ model, where }) => {
|
|
149
|
+
return 0;
|
|
150
|
+
},
|
|
151
|
+
createSchema: async ({ file, tables }) => {
|
|
152
|
+
file != null ? file : file = "./auth.schema.ts";
|
|
153
|
+
return createSchema(file, tables, usePlural);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export { instantAdapter };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** biome-ignore-all lint/suspicious/noExplicitAny: any thing goes */
|
|
2
|
+
import { type InstantAdminDatabase } from "@instantdb/admin";
|
|
3
|
+
import { type DBAdapterDebugLogOption, type Where } from "better-auth/adapters";
|
|
4
|
+
/**
|
|
5
|
+
* The InstantDB adapter config options.
|
|
6
|
+
*/
|
|
7
|
+
interface InstantAdapterConfig {
|
|
8
|
+
/**
|
|
9
|
+
* The InstantDB admin database instance.
|
|
10
|
+
*/
|
|
11
|
+
db: InstantAdminDatabase<any, any>;
|
|
12
|
+
/**
|
|
13
|
+
* If the table names in the schema are plural.
|
|
14
|
+
*/
|
|
15
|
+
usePlural?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Helps you debug issues with the adapter.
|
|
18
|
+
*/
|
|
19
|
+
debugLogs?: DBAdapterDebugLogOption;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The InstantDB adapter.
|
|
23
|
+
*/
|
|
24
|
+
export declare const instantAdapter: ({ db, usePlural, debugLogs }: InstantAdapterConfig) => import("better-auth/adapters").AdapterFactory;
|
|
25
|
+
export declare function parseWhere(where?: Where[]): Record<string, unknown>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/** biome-ignore-all lint/suspicious/noExplicitAny: any thing goes */
|
|
2
|
+
import { id } from "@instantdb/admin";
|
|
3
|
+
import { createAdapterFactory } from "better-auth/adapters";
|
|
4
|
+
import { createSchema } from "./create-schema";
|
|
5
|
+
import { prettyPrint } from "./utils";
|
|
6
|
+
/**
|
|
7
|
+
* The InstantDB adapter.
|
|
8
|
+
*/
|
|
9
|
+
export const instantAdapter = ({ db, usePlural = true, debugLogs = false }) => {
|
|
10
|
+
return createAdapterFactory({
|
|
11
|
+
config: {
|
|
12
|
+
customIdGenerator: id,
|
|
13
|
+
adapterId: "instantdb-adapter", // A unique identifier for the adapter.
|
|
14
|
+
adapterName: "InstantDB Adapter", // The name of the adapter.
|
|
15
|
+
usePlural, // Whether the table names in the schema are plural.
|
|
16
|
+
debugLogs, // Whether to enable debug logs.
|
|
17
|
+
supportsJSON: true, // Whether the database supports JSON. (Default: false)
|
|
18
|
+
supportsDates: false, // Whether the database supports dates. (Default: true)
|
|
19
|
+
supportsBooleans: true, // Whether the database supports booleans. (Default: true)
|
|
20
|
+
supportsNumericIds: false // Whether the database supports auto-incrementing numeric IDs. (Default: true)
|
|
21
|
+
},
|
|
22
|
+
adapter: ({ debugLog, getDefaultModelName, getFieldName }) => {
|
|
23
|
+
return {
|
|
24
|
+
create: async ({ data, model }) => {
|
|
25
|
+
// Create the InstantDB token and override session.token
|
|
26
|
+
if (getDefaultModelName(model) === "session") {
|
|
27
|
+
// Get the $users entity for this session's userId with the user link
|
|
28
|
+
const result = await db.query({
|
|
29
|
+
$users: { $: { where: { id: data.userId } } }
|
|
30
|
+
});
|
|
31
|
+
const $users = result.$users;
|
|
32
|
+
if (!$users.length) {
|
|
33
|
+
throw new Error(`$users entity not found: ${data.userId}`);
|
|
34
|
+
}
|
|
35
|
+
const $user = $users[0];
|
|
36
|
+
// Create the InstantDB token and override session.token
|
|
37
|
+
debugLog("Create Token", $user.email);
|
|
38
|
+
const token = await db.auth.createToken($user.email);
|
|
39
|
+
const tokenField = getFieldName({ model, field: "token" });
|
|
40
|
+
// @ts-expect-error
|
|
41
|
+
data[tokenField] = token;
|
|
42
|
+
}
|
|
43
|
+
if (getDefaultModelName(model) === "user") {
|
|
44
|
+
model = "$users";
|
|
45
|
+
}
|
|
46
|
+
debugLog("Create", model, prettyPrint(data));
|
|
47
|
+
await db.transact([db.tx[model][data.id].create(data)]);
|
|
48
|
+
return data;
|
|
49
|
+
},
|
|
50
|
+
update: async ({ update, model, where }) => {
|
|
51
|
+
if (getDefaultModelName(model) === "user") {
|
|
52
|
+
model = "$users";
|
|
53
|
+
}
|
|
54
|
+
const query = { [model]: { $: { where: parseWhere(where) } } };
|
|
55
|
+
debugLog("Query", prettyPrint(query));
|
|
56
|
+
const result = await db.query(query);
|
|
57
|
+
debugLog("Result", prettyPrint(result));
|
|
58
|
+
const entities = result[model];
|
|
59
|
+
if (!entities.length)
|
|
60
|
+
return null;
|
|
61
|
+
debugLog("Update:", entities.map((entity) => entity.id), prettyPrint(update));
|
|
62
|
+
const transactions = entities.map((entity) => db.tx[model][entity.id].update(update));
|
|
63
|
+
await db.transact(transactions);
|
|
64
|
+
return { ...entities[0], ...update };
|
|
65
|
+
},
|
|
66
|
+
updateMany: async ({ update, model, where }) => {
|
|
67
|
+
if (getDefaultModelName(model) === "user") {
|
|
68
|
+
model = "$users";
|
|
69
|
+
}
|
|
70
|
+
const query = { [model]: { $: { where: parseWhere(where) } } };
|
|
71
|
+
debugLog("Query", prettyPrint(query));
|
|
72
|
+
const result = await db.query(query);
|
|
73
|
+
debugLog("Result", prettyPrint(result));
|
|
74
|
+
const entities = result[model];
|
|
75
|
+
debugLog("Update:", entities.map((entity) => entity.id), prettyPrint(update));
|
|
76
|
+
const transactions = entities.map((entity) => db.tx[model][entity.id].update(update));
|
|
77
|
+
await db.transact(transactions);
|
|
78
|
+
return entities.length;
|
|
79
|
+
},
|
|
80
|
+
delete: async ({ model, where }) => {
|
|
81
|
+
if (getDefaultModelName(model) === "user") {
|
|
82
|
+
model = "$users";
|
|
83
|
+
}
|
|
84
|
+
const query = { [model]: { $: { where: parseWhere(where) } } };
|
|
85
|
+
debugLog("Query", prettyPrint(query));
|
|
86
|
+
const result = await db.query(query);
|
|
87
|
+
debugLog("Result", prettyPrint(result));
|
|
88
|
+
const entities = result[model];
|
|
89
|
+
const transactions = entities.map((entity) => db.tx[model][entity.id].delete());
|
|
90
|
+
await db.transact(transactions);
|
|
91
|
+
if (getDefaultModelName(model) === "session") {
|
|
92
|
+
Promise.all(entities.map(async (entity) => {
|
|
93
|
+
try {
|
|
94
|
+
const tokenField = getFieldName({ model, field: "token" });
|
|
95
|
+
await db.auth.signOut({
|
|
96
|
+
refresh_token: entity[tokenField]
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
catch (_a) { }
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
deleteMany: async ({ model, where }) => {
|
|
104
|
+
if (getDefaultModelName(model) === "user") {
|
|
105
|
+
model = "$users";
|
|
106
|
+
}
|
|
107
|
+
const query = { [model]: { $: { where: parseWhere(where) } } };
|
|
108
|
+
debugLog("Query", prettyPrint(query));
|
|
109
|
+
const result = await db.query(query);
|
|
110
|
+
debugLog("Result", prettyPrint(result));
|
|
111
|
+
const entities = result[model];
|
|
112
|
+
const transactions = entities.map((entity) => db.tx[model][entity.id].delete());
|
|
113
|
+
await db.transact(transactions);
|
|
114
|
+
if (getDefaultModelName(model) === "session") {
|
|
115
|
+
Promise.all(entities.map(async (entity) => {
|
|
116
|
+
try {
|
|
117
|
+
const tokenField = getFieldName({ model, field: "token" });
|
|
118
|
+
await db.auth.signOut({
|
|
119
|
+
refresh_token: entity[tokenField]
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch (_a) { }
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
return entities.length;
|
|
126
|
+
},
|
|
127
|
+
findOne: async ({ model, where }) => {
|
|
128
|
+
if (getDefaultModelName(model) === "user") {
|
|
129
|
+
model = "$users";
|
|
130
|
+
}
|
|
131
|
+
const query = { [model]: { $: { where: parseWhere(where) } } };
|
|
132
|
+
debugLog("Query", prettyPrint(query));
|
|
133
|
+
const result = await db.query(query);
|
|
134
|
+
debugLog("Result", prettyPrint(result));
|
|
135
|
+
const entities = result[model];
|
|
136
|
+
if (entities.length)
|
|
137
|
+
return entities[0];
|
|
138
|
+
return null;
|
|
139
|
+
},
|
|
140
|
+
findMany: async ({ model, where, limit, sortBy, offset }) => {
|
|
141
|
+
if (getDefaultModelName(model) === "user") {
|
|
142
|
+
model = "$users";
|
|
143
|
+
}
|
|
144
|
+
let order;
|
|
145
|
+
if (sortBy) {
|
|
146
|
+
order = {
|
|
147
|
+
[sortBy.field]: sortBy.direction
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const query = {
|
|
151
|
+
[model]: { $: { where: parseWhere(where), limit, offset, order } }
|
|
152
|
+
};
|
|
153
|
+
debugLog("Query", prettyPrint(query));
|
|
154
|
+
const result = await db.query(query);
|
|
155
|
+
debugLog("Result", prettyPrint(result));
|
|
156
|
+
const entities = result[model];
|
|
157
|
+
return entities;
|
|
158
|
+
},
|
|
159
|
+
count: async ({ model, where }) => {
|
|
160
|
+
if (getDefaultModelName(model) === "user") {
|
|
161
|
+
model = "$users";
|
|
162
|
+
}
|
|
163
|
+
const query = { [model]: { $: { where: parseWhere(where) } } };
|
|
164
|
+
debugLog("Query", prettyPrint(query));
|
|
165
|
+
const result = await db.query(query);
|
|
166
|
+
debugLog("Result", prettyPrint(result));
|
|
167
|
+
const entities = result[model];
|
|
168
|
+
return entities.length;
|
|
169
|
+
},
|
|
170
|
+
createSchema: async ({ file, tables }) => {
|
|
171
|
+
return createSchema(file !== null && file !== void 0 ? file : "./auth.schema.ts", tables, usePlural);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
export function parseWhere(where) {
|
|
178
|
+
const whereQuery = {};
|
|
179
|
+
where === null || where === void 0 ? void 0 : where.forEach((item) => {
|
|
180
|
+
switch (item.operator) {
|
|
181
|
+
case "eq":
|
|
182
|
+
whereQuery[item.field] = item.value;
|
|
183
|
+
break;
|
|
184
|
+
case "in":
|
|
185
|
+
whereQuery[item.field] = { $in: item.value };
|
|
186
|
+
break;
|
|
187
|
+
case "contains":
|
|
188
|
+
whereQuery[item.field] = { $like: `%${item.value}%` };
|
|
189
|
+
break;
|
|
190
|
+
case "starts_with":
|
|
191
|
+
whereQuery[item.field] = { $like: `${item.value}%` };
|
|
192
|
+
break;
|
|
193
|
+
case "ends_with":
|
|
194
|
+
whereQuery[item.field] = { $like: `%${item.value}` };
|
|
195
|
+
break;
|
|
196
|
+
case "ne":
|
|
197
|
+
whereQuery[item.field] = { $not: item.value };
|
|
198
|
+
break;
|
|
199
|
+
case "gt":
|
|
200
|
+
whereQuery[item.field] = { $gt: item.value };
|
|
201
|
+
break;
|
|
202
|
+
case "gte":
|
|
203
|
+
whereQuery[item.field] = { $gte: item.value };
|
|
204
|
+
break;
|
|
205
|
+
case "lt":
|
|
206
|
+
whereQuery[item.field] = { $lt: item.value };
|
|
207
|
+
break;
|
|
208
|
+
case "lte":
|
|
209
|
+
whereQuery[item.field] = { $lte: item.value };
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
return whereQuery;
|
|
214
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instant-adapter.js","sourceRoot":"","sources":["../src/instant-adapter.ts"],"names":[],"mappings":";;;AACA,mDAG6B;AAC7B,mDAA8C;AAgBvC,MAAM,cAAc,GAAG,CAAC,MAA4B,EAAE,EAAE;;IAC7D,OAAA,IAAA,+BAAoB,EAAC;QACnB,MAAM,EAAE;YACN,SAAS,EAAE,mBAAmB,EAAE,uCAAuC;YACvE,WAAW,EAAE,mBAAmB,EAAE,2BAA2B;YAC7D,SAAS,EAAE,MAAA,MAAM,CAAC,SAAS,mCAAI,KAAK,EAAE,oDAAoD;YAC1F,SAAS,EAAE,MAAA,MAAM,CAAC,SAAS,mCAAI,KAAK,EAAE,gCAAgC;YACtE,YAAY,EAAE,IAAI,EAAE,uDAAuD;YAC3E,aAAa,EAAE,IAAI,EAAE,uDAAuD;YAC5E,gBAAgB,EAAE,IAAI,EAAE,0DAA0D;YAClF,kBAAkB,EAAE,KAAK,CAAC,+EAA+E;SAC1G;QACD,OAAO,EAAE,CAAC,EACR,OAAO,EACP,MAAM,EACN,QAAQ,EACR,mBAAmB,EACnB,mBAAmB,EACpB,EAAE,EAAE;YACH,OAAO;gBACL,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;oBACxC,IAAI,mBAAmB,CAAC,KAAK,CAAC,KAAK,MAAM,EAAE,CAAC;wBAC1C,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,CAAA;oBAClC,CAAC;oBAED,6CAA6C;oBAC7C,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;gBACpC,CAAC;gBACD,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;oBACzC,OAAO,IAAI,CAAA;gBACb,CAAC;gBACD,UAAU,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;oBAC7C,OAAO,CAAC,CAAA;gBACV,CAAC;gBACD,MAAM,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;oBACjC,OAAM;gBACR,CAAC;gBACD,UAAU,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;oBACrC,OAAO,CAAC,CAAA;gBACV,CAAC;gBACD,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;oBAC1C,OAAO,IAAI,CAAA;gBACb,CAAC;gBACD,QAAQ,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;oBAC1D,OAAO,EAAE,CAAA;gBACX,CAAC;gBACD,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;oBAChC,OAAO,CAAC,CAAA;gBACV,CAAC;gBACD,YAAY,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;oBACvC,IAAI,aAAJ,IAAI,cAAJ,IAAI,IAAJ,IAAI,GAAK,kBAAkB,EAAA;oBAC3B,OAAO,IAAA,4BAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAA;gBACnC,CAAC;aACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;CAAA,CAAA;AAvDS,QAAA,cAAc,kBAuDvB"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { EntitiesDef, InstantReactWebDatabase, InstantSchemaDef, LinksDef, RoomsDef } from "@instantdb/react";
|
|
2
|
+
import type { Session } from "better-auth";
|
|
3
|
+
export declare function instantAuth<TSchema extends InstantSchemaDef<EntitiesDef, LinksDef<EntitiesDef>, RoomsDef>>(db: InstantReactWebDatabase<TSchema>, session?: Session): Promise<void>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export async function instantAuth(db, session) {
|
|
2
|
+
const user = await db.getAuth();
|
|
3
|
+
if (session && (user === null || user === void 0 ? void 0 : user.id) !== (session === null || session === void 0 ? void 0 : session.userId)) {
|
|
4
|
+
db.auth.signInWithToken(session.token);
|
|
5
|
+
}
|
|
6
|
+
if (user && !session) {
|
|
7
|
+
db.auth.signOut();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { EntitiesDef, InstantReactWebDatabase, InstantSchemaDef, LinksDef, RoomsDef } from "@instantdb/react";
|
|
2
|
+
import type { Session } from "better-auth";
|
|
3
|
+
export declare function instantAuth<TSchema extends InstantSchemaDef<EntitiesDef, LinksDef<EntitiesDef>, RoomsDef>>(db: InstantReactWebDatabase<TSchema>, session?: Session): Promise<void>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export async function instantAuth(db, session) {
|
|
2
|
+
const user = await db.getAuth();
|
|
3
|
+
if (session && (user === null || user === void 0 ? void 0 : user.id) !== (session === null || session === void 0 ? void 0 : session.userId)) {
|
|
4
|
+
db.auth.signInWithToken(session.token);
|
|
5
|
+
}
|
|
6
|
+
if (user && !session) {
|
|
7
|
+
db.auth.signOut();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pretty an object.
|
|
3
|
+
* @param object - The object to pretty.
|
|
4
|
+
* @returns The pretty object.
|
|
5
|
+
*/
|
|
6
|
+
export declare function prettyObject(object: unknown): string;
|
|
7
|
+
/**
|
|
8
|
+
* Converts a field name to a relationship label
|
|
9
|
+
* e.g., "userId" -> "user", "organizationId" -> "organization"
|
|
10
|
+
* If field doesn't end with "id", uses the target model name
|
|
11
|
+
*/
|
|
12
|
+
export declare function fieldNameToLabel(fieldName: string, targetModel: string): string;
|