cloudbase-sdkv1 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/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # Cloudbase
2
+
3
+ Cloudbase is a lightweight, server-side SDK to switch between cloud providers with a unified API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install cloudbase
9
+ ```
10
+
11
+ ## Configuration
12
+
13
+ Create `cloudbase.config.js` in your project root:
14
+
15
+ ```js
16
+ module.exports = {
17
+ provider: "supabase",
18
+ url: "https://your-project.supabase.co",
19
+ key: "your-service-key"
20
+ }
21
+ ```
22
+
23
+ For Firebase (server-side):
24
+
25
+ ```js
26
+ module.exports = {
27
+ provider: "firebase",
28
+ serviceAccount: require("./serviceAccount.json"),
29
+ storageBucket: "your-project-id.appspot.com"
30
+ }
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ```js
36
+ const { createClient } = require("cloudbase")
37
+
38
+ const db = createClient()
39
+
40
+ const User = db.model("users")
41
+
42
+ await User.create({ name: "Aman", age: 21 })
43
+
44
+ const adults = await User.find({ age: { gt: 18 } })
45
+
46
+ const one = await User.findOne({ age: { gt: 18 } })
47
+ ```
48
+
49
+ ### Pagination
50
+
51
+ ```js
52
+ await User.find({}, { limit: 10, offset: 0 })
53
+ ```
54
+
55
+ ### Sorting
56
+
57
+ ```js
58
+ await User.find({}, { orderBy: "age", order: "desc" })
59
+ ```
60
+
61
+ ## Auth
62
+
63
+ ```js
64
+ const auth = db.auth()
65
+
66
+ await auth.signup("user@example.com", "password123")
67
+ await auth.signin("user@example.com")
68
+ await auth.logout()
69
+ ```
70
+
71
+ ### Firebase server-side helpers
72
+
73
+ ```js
74
+ const auth = db.auth()
75
+ const link = await auth.generateSignInWithEmailLink("user@example.com", actionCodeSettings)
76
+ const reset = await auth.generatePasswordResetLink("user@example.com", actionCodeSettings)
77
+ ```
78
+
79
+ ## Storage
80
+
81
+ ```js
82
+ const storage = db.storage()
83
+ await storage.upload("avatars/user-1.png", buffer)
84
+ const url = await storage.downloadUrl("avatars/user-1.png")
85
+ ```
86
+
87
+ ## Unified Errors
88
+
89
+ All provider errors are wrapped as:
90
+
91
+ ```js
92
+ {
93
+ name: "CloudbaseError",
94
+ type: "AUTH_ERROR" | "DB_ERROR" | "STORAGE_ERROR" | "CONFIG_ERROR",
95
+ message: "..."
96
+ }
97
+ ```
@@ -0,0 +1,18 @@
1
+ const FirebaseAuth = require("./firebaseAuth")
2
+ const SupabaseAuth = require("./supbaseAuth")
3
+
4
+ const authProviders = {
5
+ firebase: FirebaseAuth,
6
+ supabase: SupabaseAuth
7
+ }
8
+
9
+ function loadAuth(provider, config){
10
+ const AuthProvider = authProviders[provider]
11
+ if (!AuthProvider) {
12
+ throw new Error("Unsupported auth provider")
13
+ }
14
+
15
+ return new AuthProvider(config)
16
+ }
17
+
18
+ module.exports = loadAuth
@@ -0,0 +1,74 @@
1
+ const getFirebaseApp = require("../providers/firebase/firebaseApp")
2
+
3
+ class FirebaseAuth {
4
+
5
+ constructor(config){
6
+ getFirebaseApp(config)
7
+ const admin = require("firebase-admin")
8
+ this.auth = admin.auth()
9
+ }
10
+
11
+ async signup(email, password){
12
+ const user = await this.auth.createUser({
13
+ email,
14
+ password
15
+ })
16
+
17
+ return { user, session: null }
18
+ }
19
+
20
+ async signin(email){
21
+ const user = await this.auth.getUserByEmail(email)
22
+ return { user, session: null }
23
+ }
24
+
25
+ async createCustomToken(uid, claims) {
26
+ const token = await this.auth.createCustomToken(uid, claims)
27
+ return { token }
28
+ }
29
+
30
+ async verifyIdToken(idToken) {
31
+ const decoded = await this.auth.verifyIdToken(idToken)
32
+ return { decoded }
33
+ }
34
+
35
+ async setCustomClaims(uid, claims) {
36
+ await this.auth.setCustomUserClaims(uid, claims)
37
+ return { success: true }
38
+ }
39
+
40
+ async generatePasswordResetLink(email, actionCodeSettings){
41
+ const link = await this.auth.generatePasswordResetLink(email, actionCodeSettings)
42
+ return { link }
43
+ }
44
+
45
+ async generateEmailVerificationLink(email, actionCodeSettings){
46
+ const link = await this.auth.generateEmailVerificationLink(email, actionCodeSettings)
47
+ return { link }
48
+ }
49
+
50
+ async generateSignInWithEmailLink(email, actionCodeSettings){
51
+ const link = await this.auth.generateSignInWithEmailLink(email, actionCodeSettings)
52
+ return { link }
53
+ }
54
+
55
+ async revokeRefreshTokens(uid){
56
+ await this.auth.revokeRefreshTokens(uid)
57
+ return { success: true }
58
+ }
59
+
60
+ async listUsers(maxResults = 1000, pageToken) {
61
+ return this.auth.listUsers(maxResults, pageToken)
62
+ }
63
+
64
+ async logout(uid){
65
+ if (!uid) {
66
+ return { success: true }
67
+ }
68
+ await this.auth.revokeRefreshTokens(uid)
69
+ return { success:true }
70
+ }
71
+
72
+ }
73
+
74
+ module.exports = FirebaseAuth
@@ -0,0 +1,91 @@
1
+ const { createClient } = require("@supabase/supabase-js")
2
+
3
+ class SupabaseAuth {
4
+
5
+ constructor(config){
6
+ this.client = createClient(config.url, config.key)
7
+ }
8
+
9
+ async signup(email, password){
10
+ return this.signupWithEmailPassword(email, password)
11
+ }
12
+
13
+ async signin(email, password){
14
+ return this.signinWithEmailPassword(email, password)
15
+ }
16
+
17
+ async signupWithEmailPassword(email, password){
18
+
19
+ const { data, error } = await this.client.auth.signUp({
20
+ email,
21
+ password
22
+ })
23
+
24
+ if(error) throw error
25
+
26
+ return {
27
+ user: data.user,
28
+ session: data.session
29
+ }
30
+ }
31
+
32
+ async signinWithEmailPassword(email, password){
33
+
34
+ const { data, error } =
35
+ await this.client.auth.signInWithPassword({
36
+ email,
37
+ password
38
+ })
39
+
40
+ if(error) throw error
41
+
42
+ return {
43
+ user: data.user,
44
+ session: data.session
45
+ }
46
+ }
47
+
48
+ async logout(){
49
+
50
+ const { error } = await this.client.auth.signOut()
51
+
52
+ if(error) throw error
53
+
54
+ return { success:true }
55
+ }
56
+
57
+ async sendEmailLink(email, options = {}){
58
+ const { data, error } = await this.client.auth.signInWithOtp({
59
+ email,
60
+ options
61
+ })
62
+
63
+ if(error) throw error
64
+
65
+ return { data }
66
+ }
67
+
68
+ async signinWithOAuth(provider, options = {}){
69
+ const { data, error } = await this.client.auth.signInWithOAuth({
70
+ provider,
71
+ options
72
+ })
73
+
74
+ if(error) throw error
75
+
76
+ return { data }
77
+ }
78
+
79
+ async handleOAuthCallback(url){
80
+ const { data, error } = await this.client.auth.exchangeCodeForSession(url)
81
+ if(error) throw error
82
+ return { data }
83
+ }
84
+
85
+ onAuthStateChange(handler){
86
+ return this.client.auth.onAuthStateChange(handler)
87
+ }
88
+
89
+ }
90
+
91
+ module.exports = SupabaseAuth
package/cli/index.js ADDED
File without changes
@@ -0,0 +1,31 @@
1
+ const fs = require("fs")
2
+ const path = require("path")
3
+ const { wrapError } = require("../packages/core/errors")
4
+
5
+ function loadConfig(providedConfig) {
6
+ if (providedConfig && typeof providedConfig === "object") {
7
+ return providedConfig
8
+ }
9
+
10
+ const configPath = path.join(process.cwd(), "cloudbase.config.js")
11
+
12
+ if (!fs.existsSync(configPath)) {
13
+ throw wrapError(
14
+ new Error("Missing cloudbase.config.js and no config provided to createClient"),
15
+ "CONFIG_ERROR",
16
+ { path: configPath }
17
+ )
18
+ }
19
+
20
+ try {
21
+ const config = require(configPath)
22
+ if (!config || typeof config !== "object") {
23
+ throw new Error("cloudbase.config.js must export an object")
24
+ }
25
+ return config
26
+ } catch (err) {
27
+ throw wrapError(err, "CONFIG_ERROR", { path: configPath })
28
+ }
29
+ }
30
+
31
+ module.exports = loadConfig
@@ -0,0 +1,15 @@
1
+ # Examples
2
+
3
+ These examples are server-side usage patterns. Replace config values with your own.
4
+
5
+ ## Supabase
6
+
7
+ ```bash
8
+ node examples/supabase.js
9
+ ```
10
+
11
+ ## Firebase
12
+
13
+ ```bash
14
+ node examples/firebase.js
15
+ ```
@@ -0,0 +1,33 @@
1
+ const { createClient } = require("..")
2
+
3
+ const db = createClient({
4
+ provider: "firebase",
5
+ serviceAccount: require("../serviceAccount.json"),
6
+ storageBucket: "your-project-id.appspot.com"
7
+ })
8
+
9
+ async function run() {
10
+ const User = db.model("users")
11
+
12
+ await User.create({ name: "Aman", age: 21 })
13
+
14
+ const adults = await User.find({ age: { gt: 18 } }, { limit: 10, offset: 0 })
15
+ console.log("Adults:", adults)
16
+
17
+ const one = await User.findOne({ age: { gt: 18 } })
18
+ console.log("One:", one)
19
+
20
+ const auth = db.auth()
21
+ await auth.generateSignInWithEmailLink("user@example.com", {
22
+ url: "https://example.com/finishSignIn",
23
+ handleCodeInApp: true
24
+ })
25
+
26
+ const storage = db.storage()
27
+ await storage.list("avatars")
28
+ }
29
+
30
+ run().catch(err => {
31
+ console.error(err)
32
+ process.exit(1)
33
+ })
@@ -0,0 +1,31 @@
1
+ const { createClient } = require("..")
2
+
3
+ const db = createClient({
4
+ provider: "supabase",
5
+ url: "project_url",
6
+ key: "your-service-key",
7
+ bucket: "public"
8
+ })
9
+
10
+ async function run() {
11
+ const User = db.model("users")
12
+
13
+ await User.create({ name: "Aman", age: 21 })
14
+
15
+ const adults = await User.find({ age: { gt: 18 } }, { limit: 10, offset: 0 })
16
+ console.log("Adults:", adults)
17
+
18
+ const one = await User.findOne({ age: { gt: 18 } })
19
+ console.log("One:", one)
20
+
21
+ const auth = db.auth()
22
+ await auth.signup("user@example.com", "password123")
23
+
24
+ const storage = db.storage().from("public")
25
+ await storage.list("", { limit: 10 })
26
+ }
27
+
28
+ run().catch(err => {
29
+ console.error(err)
30
+ process.exit(1)
31
+ })
package/index.js ADDED
@@ -0,0 +1,5 @@
1
+ const createClient = require("./packages/core/client")
2
+
3
+ module.exports = {
4
+ createClient
5
+ }
package/orm/model.js ADDED
@@ -0,0 +1,31 @@
1
+ class Model {
2
+
3
+ constructor(name, client) {
4
+ this.name = name
5
+ this.client = client
6
+ }
7
+
8
+ async create(data) {
9
+ return this.client.insert(this.name, data)
10
+ }
11
+
12
+ async find(query = {}, options = {}) {
13
+ return this.client.find(this.name, query, options)
14
+ }
15
+
16
+ async findOne(query = {}, options = {}) {
17
+ const results = await this.find(query, { ...options, limit: 1 })
18
+ return results && results.length ? results[0] : null
19
+ }
20
+
21
+ async update(query, data) {
22
+ return this.client.update(this.name, query, data)
23
+ }
24
+
25
+ async delete(query) {
26
+ return this.client.delete(this.name, query)
27
+ }
28
+
29
+ }
30
+
31
+ module.exports = Model
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "cloudbase-sdkv1",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "scripts": {
6
+ "test": "echo \"Error: no test specified\" && exit 1"
7
+ },
8
+ "author": "",
9
+ "license": "ISC",
10
+ "description": "",
11
+ "dependencies": {
12
+ "@supabase/supabase-js": "^2.99.1",
13
+ "firebase-admin": "^13.7.0"
14
+ },
15
+ "devDependencies": {
16
+ "tsup": "^8.5.1",
17
+ "typescript": "^5.9.3"
18
+ }
19
+ }
@@ -0,0 +1,78 @@
1
+ const getFirebaseApp = require("../../../providers/firebase/firebaseApp")
2
+ const parseQuery = require("../../../parser/queryParser")
3
+
4
+ class FirebaseAdapter {
5
+
6
+ constructor(config) {
7
+ getFirebaseApp(config)
8
+ const admin = require("firebase-admin")
9
+ this.db = admin.firestore()
10
+ }
11
+
12
+ async insert(collectionName, data) {
13
+ return this.db.collection(collectionName).add(data)
14
+ }
15
+
16
+ async find(collectionName, queryObject = {}, options = {}) {
17
+ const conditions = parseQuery(queryObject)
18
+ let request = this.db.collection(collectionName)
19
+
20
+ for (const cond of conditions) {
21
+ let op = cond.operator
22
+ if (cond.operator === "eq") op = "=="
23
+ if (cond.operator === "gt") op = ">"
24
+ if (cond.operator === "lt") op = "<"
25
+ if (cond.operator === "gte") op = ">="
26
+ if (cond.operator === "lte") op = "<="
27
+ request = request.where(cond.field, op, cond.value)
28
+ }
29
+
30
+ if (options.orderBy) {
31
+ const direction = options.order === "desc" ? "desc" : "asc"
32
+ request = request.orderBy(options.orderBy, direction)
33
+ }
34
+
35
+ if (Number.isInteger(options.limit)) {
36
+ request = request.limit(options.limit)
37
+ }
38
+
39
+ if (Number.isInteger(options.offset)) {
40
+ request = request.offset(options.offset)
41
+ }
42
+
43
+ const snapshot = await request.get()
44
+ return snapshot.docs.map(docSnap => ({ id: docSnap.id, ...docSnap.data() }))
45
+ }
46
+
47
+ async update(collectionName, queryObject, data) {
48
+ const { ids, docs } = await this._resolveDocs(collectionName, queryObject)
49
+ const updates = docs.map((docRef, index) => docRef.update(data).then(() => ids[index]))
50
+ return Promise.all(updates)
51
+ }
52
+
53
+ async delete(collectionName, queryObject) {
54
+ const { ids, docs } = await this._resolveDocs(collectionName, queryObject)
55
+ const deletions = docs.map((docRef, index) => docRef.delete().then(() => ids[index]))
56
+ return Promise.all(deletions)
57
+ }
58
+
59
+ async _resolveDocs(collectionName, queryObject = {}) {
60
+ if (queryObject && (queryObject.id || queryObject._id)) {
61
+ const id = queryObject.id || queryObject._id
62
+ return {
63
+ ids: [id],
64
+ docs: [this.db.collection(collectionName).doc(id)]
65
+ }
66
+ }
67
+
68
+ const results = await this.find(collectionName, queryObject)
69
+ const ids = results.map(item => item.id).filter(Boolean)
70
+ return {
71
+ ids,
72
+ docs: ids.map(id => this.db.collection(collectionName).doc(id))
73
+ }
74
+ }
75
+
76
+ }
77
+
78
+ module.exports = FirebaseAdapter
@@ -0,0 +1,121 @@
1
+ const { createClient } = require("@supabase/supabase-js")
2
+ const parseQuery = require("../../../parser/queryParser")
3
+
4
+ class SupabaseAdapter {
5
+
6
+ constructor(config) {
7
+ this.client = createClient(config.url, config.key)
8
+ }
9
+
10
+ async insert(table, data) {
11
+ return this.client.from(table).insert(data)
12
+ }
13
+
14
+
15
+ async find(table, query = {}, options = {}) {
16
+
17
+ const conditions = parseQuery(query)
18
+
19
+ let request = this.client.from(table).select("*")
20
+
21
+ for (const cond of conditions) {
22
+
23
+ if (cond.operator === "eq") {
24
+ request = request.eq(cond.field, cond.value)
25
+ }
26
+
27
+ if (cond.operator === "gt") {
28
+ request = request.gt(cond.field, cond.value)
29
+ }
30
+
31
+ if (cond.operator === "gte") {
32
+ request = request.gte(cond.field, cond.value)
33
+ }
34
+
35
+ if (cond.operator === "lt") {
36
+ request = request.lt(cond.field, cond.value)
37
+ }
38
+
39
+ if (cond.operator === "lte") {
40
+ request = request.lte(cond.field, cond.value)
41
+ }
42
+
43
+ }
44
+
45
+ if (options.orderBy) {
46
+ const ascending = options.order !== "desc"
47
+ request = request.order(options.orderBy, { ascending })
48
+ }
49
+
50
+ if (Number.isInteger(options.offset) && Number.isInteger(options.limit)) {
51
+ request = request.range(options.offset, options.offset + options.limit - 1)
52
+ } else if (Number.isInteger(options.limit)) {
53
+ request = request.limit(options.limit)
54
+ }
55
+
56
+ const { data, error } = await request
57
+
58
+ if (error) throw error
59
+
60
+ return data
61
+ }
62
+
63
+ async update(table, query = {}, data) {
64
+ const conditions = parseQuery(query)
65
+
66
+ let request = this.client.from(table).update(data)
67
+
68
+ for (const cond of conditions) {
69
+ if (cond.operator === "eq") {
70
+ request = request.eq(cond.field, cond.value)
71
+ }
72
+ if (cond.operator === "gt") {
73
+ request = request.gt(cond.field, cond.value)
74
+ }
75
+ if (cond.operator === "gte") {
76
+ request = request.gte(cond.field, cond.value)
77
+ }
78
+ if (cond.operator === "lt") {
79
+ request = request.lt(cond.field, cond.value)
80
+ }
81
+ if (cond.operator === "lte") {
82
+ request = request.lte(cond.field, cond.value)
83
+ }
84
+ }
85
+
86
+ const { data: updated, error } = await request.select()
87
+ if (error) throw error
88
+ return updated
89
+ }
90
+
91
+ async delete(table, query = {}) {
92
+ const conditions = parseQuery(query)
93
+
94
+ let request = this.client.from(table).delete()
95
+
96
+ for (const cond of conditions) {
97
+ if (cond.operator === "eq") {
98
+ request = request.eq(cond.field, cond.value)
99
+ }
100
+ if (cond.operator === "gt") {
101
+ request = request.gt(cond.field, cond.value)
102
+ }
103
+ if (cond.operator === "gte") {
104
+ request = request.gte(cond.field, cond.value)
105
+ }
106
+ if (cond.operator === "lt") {
107
+ request = request.lt(cond.field, cond.value)
108
+ }
109
+ if (cond.operator === "lte") {
110
+ request = request.lte(cond.field, cond.value)
111
+ }
112
+ }
113
+
114
+ const { data: deleted, error } = await request.select()
115
+ if (error) throw error
116
+ return deleted
117
+ }
118
+
119
+ }
120
+
121
+ module.exports = SupabaseAdapter
@@ -0,0 +1,18 @@
1
+ const FirebaseAdapter = require("../adapters/firebase")
2
+ const SupabaseAdapter = require("../adapters/supabase")
3
+
4
+ const adapterProviders = {
5
+ firebase: FirebaseAdapter,
6
+ supabase: SupabaseAdapter
7
+ }
8
+
9
+ function loadAdapter(provider, config) {
10
+ const Adapter = adapterProviders[provider]
11
+ if (!Adapter) {
12
+ throw new Error("Unsupported provider")
13
+ }
14
+
15
+ return new Adapter(config)
16
+ }
17
+
18
+ module.exports = loadAdapter
@@ -0,0 +1,81 @@
1
+ const loadAdapter = require("./adapterLoader")
2
+ const Model = require("../../orm/model")
3
+ const loadAuth = require("../../auth/authLoader")
4
+ const loadStorage = require("../../storage/storageLoader")
5
+ const loadConfig = require("../../config/configLoader")
6
+ const { wrapError } = require("./errors")
7
+
8
+ function wrapProvider(provider, type) {
9
+ return new Proxy(provider, {
10
+ get(target, prop) {
11
+ const value = target[prop]
12
+ if (typeof value !== "function") {
13
+ return value
14
+ }
15
+ return (...args) => {
16
+ try {
17
+ const result = value.apply(target, args)
18
+ if (result && typeof result.then === "function") {
19
+ return result.catch(err => {
20
+ throw wrapError(err, type)
21
+ })
22
+ }
23
+ return result
24
+ } catch (err) {
25
+ throw wrapError(err, type)
26
+ }
27
+ }
28
+ }
29
+ })
30
+ }
31
+
32
+ class CloudClient {
33
+
34
+ constructor(config){
35
+ this.config = config
36
+ this.adapter = wrapProvider(loadAdapter(config.provider, config), "DB_ERROR")
37
+ this.authProvider = wrapProvider(loadAuth(config.provider, config), "AUTH_ERROR")
38
+ this.storageProvider = wrapProvider(loadStorage(config.provider, config), "STORAGE_ERROR")
39
+ this.capabilities = {
40
+ auth: true,
41
+ database: true,
42
+ storage: true
43
+ }
44
+ }
45
+
46
+ model(name){
47
+ return new Model(name, this)
48
+ }
49
+
50
+ auth(){
51
+ return this.authProvider
52
+ }
53
+
54
+ storage(){
55
+ return this.storageProvider
56
+ }
57
+
58
+ async insert(collection, data) {
59
+ return this.adapter.insert(collection, data)
60
+ }
61
+
62
+ async find(collection, query, options) {
63
+ return this.adapter.find(collection, query, options)
64
+ }
65
+
66
+ async update(collection, query, data) {
67
+ return this.adapter.update(collection, query, data)
68
+ }
69
+
70
+ async delete(collection, query) {
71
+ return this.adapter.delete(collection, query)
72
+ }
73
+
74
+ }
75
+
76
+ function createClient(config) {
77
+ const resolvedConfig = loadConfig(config)
78
+ return new CloudClient(resolvedConfig)
79
+ }
80
+
81
+ module.exports = createClient
@@ -0,0 +1,23 @@
1
+ class CloudbaseError extends Error {
2
+ constructor(type, message, details = {}, cause = null) {
3
+ super(message)
4
+ this.name = "CloudbaseError"
5
+ this.type = type
6
+ this.details = details
7
+ this.cause = cause
8
+ }
9
+ }
10
+
11
+ function wrapError(err, type, details = {}) {
12
+ if (err instanceof CloudbaseError) {
13
+ return err
14
+ }
15
+
16
+ const message = err && err.message ? err.message : "Unknown error"
17
+ return new CloudbaseError(type, message, details, err)
18
+ }
19
+
20
+ module.exports = {
21
+ CloudbaseError,
22
+ wrapError
23
+ }
@@ -0,0 +1,58 @@
1
+ function parseQuery(query) {
2
+
3
+ const conditions = []
4
+
5
+ for (const field in query) {
6
+
7
+ const value = query[field]
8
+
9
+ if (typeof value === "object") {
10
+
11
+ if (value.gt) {
12
+ conditions.push({
13
+ field,
14
+ operator: "gt",
15
+ value: value.gt
16
+ })
17
+ }
18
+
19
+ if (value.gte) {
20
+ conditions.push({
21
+ field,
22
+ operator: "gte",
23
+ value: value.gte
24
+ })
25
+ }
26
+
27
+ if (value.lt) {
28
+ conditions.push({
29
+ field,
30
+ operator: "lt",
31
+ value: value.lt
32
+ })
33
+ }
34
+
35
+ if (value.lte) {
36
+ conditions.push({
37
+ field,
38
+ operator: "lte",
39
+ value: value.lte
40
+ })
41
+ }
42
+
43
+ } else {
44
+
45
+ conditions.push({
46
+ field,
47
+ operator: "eq",
48
+ value
49
+ })
50
+
51
+ }
52
+
53
+ }
54
+
55
+ return conditions
56
+ }
57
+
58
+ module.exports = parseQuery
@@ -0,0 +1,18 @@
1
+ const admin = require("firebase-admin")
2
+
3
+ function getFirebaseApp(config) {
4
+ if (!config.serviceAccount) {
5
+ throw new Error("Missing firebase serviceAccount in config")
6
+ }
7
+
8
+ if (admin.apps.length) {
9
+ return admin.app()
10
+ }
11
+
12
+ return admin.initializeApp({
13
+ credential: admin.credential.cert(config.serviceAccount),
14
+ storageBucket: config.storageBucket
15
+ })
16
+ }
17
+
18
+ module.exports = getFirebaseApp
@@ -0,0 +1,35 @@
1
+ const getFirebaseApp = require("../providers/firebase/firebaseApp")
2
+
3
+ class FirebaseStorage {
4
+ constructor(config) {
5
+ getFirebaseApp(config)
6
+ const admin = require("firebase-admin")
7
+ this.bucket = admin.storage().bucket()
8
+ }
9
+
10
+ async upload(path, file, metadata) {
11
+ const fileRef = this.bucket.file(path)
12
+ await fileRef.save(file, { metadata })
13
+ return { path }
14
+ }
15
+
16
+ async downloadUrl(path) {
17
+ const [url] = await this.bucket.file(path).getSignedUrl({
18
+ action: "read",
19
+ expires: Date.now() + 60 * 60 * 1000
20
+ })
21
+ return { url }
22
+ }
23
+
24
+ async list(path) {
25
+ const [files] = await this.bucket.getFiles({ prefix: path })
26
+ return files.map(file => ({ name: file.name, path: file.name }))
27
+ }
28
+
29
+ async remove(path) {
30
+ await this.bucket.file(path).delete()
31
+ return { success: true }
32
+ }
33
+ }
34
+
35
+ module.exports = FirebaseStorage
@@ -0,0 +1,18 @@
1
+ const FirebaseStorage = require("./firebaseStorage")
2
+ const SupabaseStorage = require("./supabaseStorage")
3
+
4
+ const storageProviders = {
5
+ firebase: FirebaseStorage,
6
+ supabase: SupabaseStorage
7
+ }
8
+
9
+ function loadStorage(provider, config) {
10
+ const StorageProvider = storageProviders[provider]
11
+ if (!StorageProvider) {
12
+ throw new Error("Unsupported storage provider")
13
+ }
14
+
15
+ return new StorageProvider(config)
16
+ }
17
+
18
+ module.exports = loadStorage
@@ -0,0 +1,64 @@
1
+ const { createClient } = require("@supabase/supabase-js")
2
+
3
+ class SupabaseStorage {
4
+ constructor(config) {
5
+ this.client = createClient(config.url, config.key)
6
+ this.bucket = config.bucket || "public"
7
+ }
8
+
9
+ from(bucket) {
10
+ this.bucket = bucket
11
+ return this
12
+ }
13
+
14
+ async upload(path, file, options = {}) {
15
+ const { data, error } = await this.client.storage
16
+ .from(this.bucket)
17
+ .upload(path, file, options)
18
+
19
+ if (error) throw error
20
+ return data
21
+ }
22
+
23
+ async download(path) {
24
+ const { data, error } = await this.client.storage
25
+ .from(this.bucket)
26
+ .download(path)
27
+
28
+ if (error) throw error
29
+ return data
30
+ }
31
+
32
+ async list(path, options = {}) {
33
+ const { data, error } = await this.client.storage
34
+ .from(this.bucket)
35
+ .list(path, options)
36
+
37
+ if (error) throw error
38
+ return data
39
+ }
40
+
41
+ async remove(paths = []) {
42
+ const { data, error } = await this.client.storage
43
+ .from(this.bucket)
44
+ .remove(paths)
45
+
46
+ if (error) throw error
47
+ return data
48
+ }
49
+
50
+ getPublicUrl(path) {
51
+ return this.client.storage.from(this.bucket).getPublicUrl(path)
52
+ }
53
+
54
+ async getSignedUrl(path, expiresIn = 60) {
55
+ const { data, error } = await this.client.storage
56
+ .from(this.bucket)
57
+ .createSignedUrl(path, expiresIn)
58
+
59
+ if (error) throw error
60
+ return data
61
+ }
62
+ }
63
+
64
+ module.exports = SupabaseStorage