@open-xamu-co/firebase-nuxt 1.0.0 → 1.1.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/CHANGELOG.md +15 -0
- package/README.md +0 -14
- package/dist/module.d.mts +50 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +137 -0
- package/dist/runtime/client/types/entities/base.d.ts +29 -0
- package/dist/runtime/client/types/entities/base.js +0 -0
- package/dist/runtime/client/types/entities/instance.d.ts +42 -0
- package/dist/runtime/client/types/entities/instance.js +0 -0
- package/dist/runtime/client/types/entities/logs.d.ts +9 -0
- package/dist/runtime/client/types/entities/logs.js +0 -0
- package/dist/runtime/client/types/entities/user.d.ts +27 -0
- package/dist/runtime/client/types/entities/user.js +0 -0
- package/dist/runtime/client/types/firestore.d.ts +55 -0
- package/dist/runtime/client/types/firestore.js +0 -0
- package/dist/runtime/client/types/index.d.ts +5 -0
- package/dist/runtime/client/types/index.js +5 -0
- package/dist/runtime/client/utils/locale.d.ts +185 -0
- package/dist/runtime/client/utils/locale.js +63 -0
- package/dist/runtime/client/utils/logger.d.ts +14 -0
- package/dist/runtime/client/utils/logger.js +65 -0
- package/dist/runtime/client/utils/resolver.d.ts +14 -0
- package/dist/runtime/client/utils/resolver.js +88 -0
- package/dist/runtime/components/ValueCellphone.d.vue.ts +24 -0
- package/dist/runtime/components/ValueCellphone.vue +21 -0
- package/dist/runtime/components/ValueCellphone.vue.d.ts +24 -0
- package/dist/runtime/components/ValueID.d.vue.ts +18 -0
- package/dist/runtime/components/ValueID.vue +14 -0
- package/dist/runtime/components/ValueID.vue.d.ts +18 -0
- package/dist/runtime/components/ValueIP.d.vue.ts +18 -0
- package/dist/runtime/components/ValueIP.vue +28 -0
- package/dist/runtime/components/ValueIP.vue.d.ts +18 -0
- package/dist/runtime/components/ValueLocation.d.vue.ts +21 -0
- package/dist/runtime/components/ValueLocation.vue +20 -0
- package/dist/runtime/components/ValueLocation.vue.d.ts +21 -0
- package/dist/runtime/components/ValuePrice.d.vue.ts +11 -0
- package/dist/runtime/components/ValuePrice.vue +12 -0
- package/dist/runtime/components/ValuePrice.vue.d.ts +11 -0
- package/dist/runtime/composables/firestore/auth.d.ts +4 -0
- package/dist/runtime/composables/firestore/auth.js +46 -0
- package/dist/runtime/composables/firestore/index.d.ts +2 -0
- package/dist/runtime/composables/firestore/index.js +2 -0
- package/dist/runtime/composables/firestore/write.d.ts +21 -0
- package/dist/runtime/composables/firestore/write.js +279 -0
- package/dist/runtime/composables/index.d.ts +4 -0
- package/dist/runtime/composables/index.js +4 -0
- package/dist/runtime/composables/store/app.d.ts +82 -0
- package/dist/runtime/composables/store/app.js +90 -0
- package/dist/runtime/composables/store/instance.d.ts +57 -0
- package/dist/runtime/composables/store/instance.js +94 -0
- package/dist/runtime/composables/store/session.d.ts +41 -0
- package/dist/runtime/composables/store/session.js +89 -0
- package/dist/runtime/composables/useAppLogger.d.ts +2 -0
- package/dist/runtime/composables/useAppLogger.js +8 -0
- package/dist/runtime/composables/useFilesUpload.d.ts +19 -0
- package/dist/runtime/composables/useFilesUpload.js +110 -0
- package/dist/runtime/composables/usePrice.d.ts +9 -0
- package/dist/runtime/composables/usePrice.js +6 -0
- package/dist/runtime/composables/useQuery.d.ts +12 -0
- package/dist/runtime/composables/useQuery.js +33 -0
- package/dist/runtime/composables/utils.d.ts +14 -0
- package/dist/runtime/composables/utils.js +65 -0
- package/dist/runtime/functions/types/entities/base.d.ts +56 -0
- package/dist/runtime/functions/types/entities/base.js +0 -0
- package/dist/runtime/functions/types/entities/instance.d.ts +73 -0
- package/dist/runtime/functions/types/entities/instance.js +0 -0
- package/dist/runtime/functions/types/entities/logs.d.ts +15 -0
- package/dist/runtime/functions/types/entities/logs.js +0 -0
- package/dist/runtime/functions/types/entities/user.d.ts +13 -0
- package/dist/runtime/functions/types/entities/user.js +0 -0
- package/dist/runtime/functions/types/index.d.ts +4 -0
- package/dist/runtime/functions/types/index.js +4 -0
- package/dist/runtime/functions/utils/encrypt.d.ts +24 -0
- package/dist/runtime/functions/utils/encrypt.js +17 -0
- package/dist/runtime/functions/utils/enums.d.ts +40 -0
- package/dist/runtime/functions/utils/enums.js +24 -0
- package/dist/runtime/functions/utils/event.d.ts +71 -0
- package/dist/runtime/functions/utils/event.js +91 -0
- package/dist/runtime/functions/utils/firebase.d.ts +7 -0
- package/dist/runtime/functions/utils/firebase.js +21 -0
- package/dist/runtime/functions/utils/logger.d.ts +3 -0
- package/dist/runtime/functions/utils/logger.js +17 -0
- package/dist/runtime/functions/utils/logs.d.ts +10 -0
- package/dist/runtime/functions/utils/logs.js +47 -0
- package/dist/runtime/functions/utils/price.d.ts +12 -0
- package/dist/runtime/functions/utils/price.js +26 -0
- package/dist/runtime/functions/utils/queue.d.ts +4 -0
- package/dist/runtime/functions/utils/queue.js +11 -0
- package/dist/runtime/functions/utils/search.d.ts +15 -0
- package/dist/runtime/functions/utils/search.js +38 -0
- package/dist/runtime/functions/utils/slugs.d.ts +2 -0
- package/dist/runtime/functions/utils/slugs.js +16 -0
- package/dist/runtime/plugins/firebase-setup.d.ts +26 -0
- package/dist/runtime/plugins/firebase-setup.js +35 -0
- package/dist/runtime/plugins/loaded.client.d.ts +2 -0
- package/dist/runtime/plugins/loaded.client.js +44 -0
- package/dist/runtime/plugins/scrollBehavior.client.d.ts +2 -0
- package/dist/runtime/plugins/scrollBehavior.client.js +20 -0
- package/dist/runtime/providers/firebase.d.ts +2 -0
- package/dist/runtime/providers/firebase.js +7 -0
- package/dist/runtime/public/js/file-upload.d.ts +1 -0
- package/dist/runtime/public/js/file-upload.js +67 -0
- package/dist/runtime/public/sample-loading.png +0 -0
- package/dist/runtime/public/sample-missing.png +0 -0
- package/dist/runtime/public/sample.png +0 -0
- package/dist/runtime/server/api/all-collection-document.get.d.ts +7 -0
- package/dist/runtime/server/api/all-collection-document.get.js +56 -0
- package/dist/runtime/server/api/all-collection.get.d.ts +8 -0
- package/dist/runtime/server/api/all-collection.get.js +67 -0
- package/dist/runtime/server/api/media.get.d.ts +8 -0
- package/dist/runtime/server/api/media.get.js +114 -0
- package/dist/runtime/server/middleware/0.hotlinking.d.ts +5 -0
- package/dist/runtime/server/middleware/0.hotlinking.js +28 -0
- package/dist/runtime/server/middleware/1.context.d.ts +5 -0
- package/dist/runtime/server/middleware/1.context.js +108 -0
- package/dist/runtime/server/types/index.d.ts +34 -0
- package/dist/runtime/server/types/index.js +0 -0
- package/dist/runtime/server/utils/auth.d.ts +10 -0
- package/dist/runtime/server/utils/auth.js +31 -0
- package/dist/runtime/server/utils/cache.d.ts +21 -0
- package/dist/runtime/server/utils/cache.js +20 -0
- package/dist/runtime/server/utils/environment.d.ts +45 -0
- package/dist/runtime/server/utils/environment.js +50 -0
- package/dist/runtime/server/utils/firebase.d.ts +9 -0
- package/dist/runtime/server/utils/firebase.js +13 -0
- package/dist/runtime/server/utils/firestore.d.ts +27 -0
- package/dist/runtime/server/utils/firestore.js +137 -0
- package/dist/runtime/server/utils/guards.d.ts +15 -0
- package/dist/runtime/server/utils/guards.js +23 -0
- package/dist/runtime/server/utils/instance.d.ts +21 -0
- package/dist/runtime/server/utils/instance.js +68 -0
- package/dist/types.d.mts +7 -0
- package/package.json +17 -17
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { deleteUser } from "firebase/auth";
|
|
2
|
+
import { defineStore, skipHydrate } from "pinia";
|
|
3
|
+
import { computed } from "vue";
|
|
4
|
+
import { useRouter } from "vue-router";
|
|
5
|
+
import { getDocumentId } from "../../client/utils/resolver.js";
|
|
6
|
+
import { useCookie, useRuntimeConfig, useSwal } from "#imports";
|
|
7
|
+
const cookieOptionsDefaults = {
|
|
8
|
+
sameSite: "strict",
|
|
9
|
+
maxAge: 365 * 24 * 60 * 60
|
|
10
|
+
// 1 year
|
|
11
|
+
};
|
|
12
|
+
export const useSessionStore = defineStore("session", () => {
|
|
13
|
+
const { production } = useRuntimeConfig().public;
|
|
14
|
+
const cookieOptions = {
|
|
15
|
+
...cookieOptionsDefaults,
|
|
16
|
+
secure: production,
|
|
17
|
+
partitioned: production
|
|
18
|
+
};
|
|
19
|
+
const token = useCookie("session.token", {
|
|
20
|
+
...cookieOptions,
|
|
21
|
+
default: () => null
|
|
22
|
+
});
|
|
23
|
+
const expiredToken = useCookie("session.expiredToken", {
|
|
24
|
+
...cookieOptions,
|
|
25
|
+
default: () => false
|
|
26
|
+
});
|
|
27
|
+
const user = useCookie("session.user", {
|
|
28
|
+
...cookieOptions,
|
|
29
|
+
partitioned: false,
|
|
30
|
+
default: () => void 0
|
|
31
|
+
});
|
|
32
|
+
const path = computed(() => {
|
|
33
|
+
const id = user.value?.id;
|
|
34
|
+
return id ? `users/${getDocumentId(id)}` : "";
|
|
35
|
+
});
|
|
36
|
+
function setToken(newToken, newExpiredToken = false) {
|
|
37
|
+
token.value = newToken || null;
|
|
38
|
+
expiredToken.value = newExpiredToken;
|
|
39
|
+
}
|
|
40
|
+
function setUser({ createdAt, updatedAt, ...userData }, token2) {
|
|
41
|
+
user.value = { ...user.value, ...userData };
|
|
42
|
+
setToken(token2, false);
|
|
43
|
+
}
|
|
44
|
+
function unsetSession(expiredToken2 = false) {
|
|
45
|
+
setToken("", expiredToken2);
|
|
46
|
+
user.value = void 0;
|
|
47
|
+
}
|
|
48
|
+
async function logout(clientAuth) {
|
|
49
|
+
if (import.meta.server) return;
|
|
50
|
+
const Swal = useSwal();
|
|
51
|
+
const { value } = await Swal.firePrevent({
|
|
52
|
+
title: "Cerrar sesion",
|
|
53
|
+
text: "\xBFEsta seguro de querer cerrar sesion?"
|
|
54
|
+
});
|
|
55
|
+
if (value) {
|
|
56
|
+
unsetSession();
|
|
57
|
+
await clientAuth?.signOut();
|
|
58
|
+
window.location.href = "/";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function remove(clientAuth) {
|
|
62
|
+
if (import.meta.server) return;
|
|
63
|
+
const router = useRouter();
|
|
64
|
+
const Swal = useSwal();
|
|
65
|
+
const { value } = await Swal.firePrevent({
|
|
66
|
+
title: "Eliminar cuenta",
|
|
67
|
+
text: "\xBFEsta seguro de querer eliminar tu cuenta?",
|
|
68
|
+
footer: "Borraremos toda tu informaci\xF3n, esta acci\xF3n no es reversible, aunque puedes volver a registrarte mas tarde"
|
|
69
|
+
});
|
|
70
|
+
const user2 = clientAuth?.currentUser;
|
|
71
|
+
if (user2 && value) {
|
|
72
|
+
await deleteUser(user2);
|
|
73
|
+
router.push("/");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
// User
|
|
78
|
+
token: skipHydrate(token),
|
|
79
|
+
expiredToken: skipHydrate(expiredToken),
|
|
80
|
+
user: skipHydrate(user),
|
|
81
|
+
// User getters
|
|
82
|
+
path,
|
|
83
|
+
// User actions
|
|
84
|
+
setUser,
|
|
85
|
+
unsetSession,
|
|
86
|
+
logout,
|
|
87
|
+
remove
|
|
88
|
+
};
|
|
89
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { makeLogger } from "../client/utils/logger.js";
|
|
2
|
+
import { useInstanceStore, useSessionStore } from "#imports";
|
|
3
|
+
export default async function useAppLogger(...args) {
|
|
4
|
+
const INSTANCE = useInstanceStore();
|
|
5
|
+
const SESSION = useSessionStore();
|
|
6
|
+
const logger = makeLogger({ instanceId: INSTANCE.id, authId: SESSION.path });
|
|
7
|
+
return logger(...args);
|
|
8
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DocumentReference } from "firebase/firestore";
|
|
2
|
+
interface UploadOptions {
|
|
3
|
+
type?: "images";
|
|
4
|
+
customMetadata?: Record<string, any>;
|
|
5
|
+
/**
|
|
6
|
+
* File upload callback
|
|
7
|
+
*
|
|
8
|
+
* Runs if not all files were uploaded
|
|
9
|
+
*/
|
|
10
|
+
uploaded?: (paths: string[]) => any;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* upload files, get urls
|
|
14
|
+
*
|
|
15
|
+
* Files should not bother with instances
|
|
16
|
+
*/
|
|
17
|
+
export default function useFilesUpload(files: File[] | undefined, targetRef: DocumentReference, // Document related to the files
|
|
18
|
+
options?: UploadOptions): Promise<string[]>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { toRaw } from "vue";
|
|
2
|
+
import { collection, doc, getDoc, increment, setDoc } from "firebase/firestore";
|
|
3
|
+
import { getToken } from "firebase/app-check";
|
|
4
|
+
import { getDocumentId } from "../client/utils/resolver.js";
|
|
5
|
+
import useAppLogger from "./useAppLogger.js";
|
|
6
|
+
import {
|
|
7
|
+
useNuxtApp,
|
|
8
|
+
useAppStore,
|
|
9
|
+
useInstanceStore,
|
|
10
|
+
useSessionStore,
|
|
11
|
+
useRuntimeConfig
|
|
12
|
+
} from "#imports";
|
|
13
|
+
export default async function useFilesUpload(files = [], targetRef, options = {}) {
|
|
14
|
+
const APP = useAppStore();
|
|
15
|
+
const SESSION = useSessionStore();
|
|
16
|
+
const INSTANCE = useInstanceStore();
|
|
17
|
+
const { $clientFirestore, $clientAppCheck } = useNuxtApp();
|
|
18
|
+
const { firebaseConfig } = useRuntimeConfig().public;
|
|
19
|
+
const appData = toRaw(firebaseConfig);
|
|
20
|
+
const { type = "images", customMetadata = {}, uploaded } = options;
|
|
21
|
+
if (!SESSION.token || !$clientFirestore || !$clientAppCheck) {
|
|
22
|
+
throw new Error("Subida no autorizada");
|
|
23
|
+
}
|
|
24
|
+
const memberId = getDocumentId(SESSION.path);
|
|
25
|
+
const memberPath = `${INSTANCE.id}/members/${memberId}`;
|
|
26
|
+
const updatedByRef = memberId ? doc($clientFirestore, memberPath) : void 0;
|
|
27
|
+
const parentCollection = targetRef.parent;
|
|
28
|
+
const grandParentDocument = parentCollection.parent;
|
|
29
|
+
const counterPath = grandParentDocument?.path || INSTANCE.id;
|
|
30
|
+
const countersCollectionRef = collection($clientFirestore, `${counterPath}/counters`);
|
|
31
|
+
const counterId = `${type}_${parentCollection.id}_${targetRef.id}`;
|
|
32
|
+
const counterRef = doc(countersCollectionRef, counterId);
|
|
33
|
+
const counterSnapshot = await getDoc(counterRef);
|
|
34
|
+
const { current = 0, createdByRef = updatedByRef } = counterSnapshot.data() || {};
|
|
35
|
+
const { token: appCheckToken } = await getToken($clientAppCheck);
|
|
36
|
+
try {
|
|
37
|
+
setDoc(
|
|
38
|
+
counterRef,
|
|
39
|
+
{ current: increment(files.length), createdByRef, updatedByRef },
|
|
40
|
+
{ merge: true }
|
|
41
|
+
);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
useAppLogger("composables:files:useFilesUpload:counter", counterRef.path, err);
|
|
44
|
+
}
|
|
45
|
+
const paths = [];
|
|
46
|
+
for (let index = 0; index < files.length; index++) {
|
|
47
|
+
const file = files[index];
|
|
48
|
+
const path = `${targetRef.path}_${current + index + 1}`;
|
|
49
|
+
const filePath = `${type}/${path}/original.${file.type.split("/")[1]}`;
|
|
50
|
+
const id = `${targetRef.id}_${file.name}`;
|
|
51
|
+
if (!file.size) {
|
|
52
|
+
useAppLogger("composables:files:useFilesUpload:map", new Error("Invalid file"), {
|
|
53
|
+
path,
|
|
54
|
+
size: file.size,
|
|
55
|
+
type: file.type,
|
|
56
|
+
name: file.name,
|
|
57
|
+
lastModified: file.lastModified
|
|
58
|
+
});
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
paths.push(path);
|
|
62
|
+
await APP.saveThumbnail(path, file);
|
|
63
|
+
APP.useQueue(
|
|
64
|
+
id,
|
|
65
|
+
`Subiendo archivo`,
|
|
66
|
+
async () => {
|
|
67
|
+
try {
|
|
68
|
+
const worker = new Worker("/js/file-upload.js", { type: "module" });
|
|
69
|
+
const uploadedSize = await new Promise((resolve, reject) => {
|
|
70
|
+
worker.postMessage({
|
|
71
|
+
filePath,
|
|
72
|
+
file,
|
|
73
|
+
customMetadata: { filePath, memberPath, ...customMetadata },
|
|
74
|
+
appData,
|
|
75
|
+
appCheckToken
|
|
76
|
+
});
|
|
77
|
+
worker.onmessage = ({ data }) => {
|
|
78
|
+
const { result, error, message, type: type2 } = data;
|
|
79
|
+
switch (type2) {
|
|
80
|
+
case "result":
|
|
81
|
+
resolve(result);
|
|
82
|
+
break;
|
|
83
|
+
case "message":
|
|
84
|
+
console.log(message);
|
|
85
|
+
break;
|
|
86
|
+
case "error":
|
|
87
|
+
console.log(message, error);
|
|
88
|
+
reject(error);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
worker.onerror = (err) => reject(err);
|
|
93
|
+
worker.onmessageerror = (err) => reject(err);
|
|
94
|
+
});
|
|
95
|
+
if (!uploadedSize) throw `No se subi\xF3 el archivo ${id}`;
|
|
96
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 * 10));
|
|
97
|
+
return `Archivo subido (${(uploadedSize / 1e6).toFixed(2)}MB)`;
|
|
98
|
+
} catch (err) {
|
|
99
|
+
paths.splice(paths.indexOf(path), 1);
|
|
100
|
+
uploaded?.(paths);
|
|
101
|
+
useAppLogger("composables:files:useFilesUpload:upload", path, err);
|
|
102
|
+
throw `No se subi\xF3 el archivo ${id}`;
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
10
|
|
106
|
+
// Minutes per upload
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return paths;
|
|
110
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NitroFetchOptions, NitroFetchRequest } from "nitropack";
|
|
2
|
+
/**
|
|
3
|
+
* Fetch wrapper with csrf token
|
|
4
|
+
*/
|
|
5
|
+
export declare function useCsrfQuery<T, R extends NitroFetchRequest = NitroFetchRequest>(url: Extract<R, string>, baseOptions?: NitroFetchOptions<R>): Promise<any>;
|
|
6
|
+
/**
|
|
7
|
+
* Fetch wrapper
|
|
8
|
+
*
|
|
9
|
+
* Refresh auth token before each request
|
|
10
|
+
* @see https://stackoverflow.com/questions/47803495/error-firebase-id-token-has-expired
|
|
11
|
+
*/
|
|
12
|
+
export declare function useQuery<T, R extends NitroFetchRequest = NitroFetchRequest>(url: Extract<R, string>, baseOptions?: NitroFetchOptions<R>): Promise<import("nitropack").TypedInternalResponse<NitroFetchRequest, T, "get">>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useRequestHeaders, useNuxtApp, useRuntimeConfig, useSessionStore } from "#imports";
|
|
2
|
+
async function getQueryOptions(baseOptions) {
|
|
3
|
+
const SESSION = useSessionStore();
|
|
4
|
+
const { $clientAuth } = useNuxtApp();
|
|
5
|
+
const { cache } = useRuntimeConfig().public;
|
|
6
|
+
const { query, ...options } = { ...baseOptions };
|
|
7
|
+
const headers = {
|
|
8
|
+
...useRequestHeaders(),
|
|
9
|
+
// Server headers (required for instance)
|
|
10
|
+
authorization: SESSION.token || "",
|
|
11
|
+
"Cache-Control": cache.frequent,
|
|
12
|
+
...options?.headers,
|
|
13
|
+
// Overrides
|
|
14
|
+
"Xamu-Context-Source": import.meta.client ? "client" : "server"
|
|
15
|
+
};
|
|
16
|
+
if (SESSION.user) {
|
|
17
|
+
if (import.meta.client) {
|
|
18
|
+
const freshToken = await $clientAuth?.currentUser?.getIdToken();
|
|
19
|
+
headers.authorization = freshToken || headers.authorization;
|
|
20
|
+
}
|
|
21
|
+
SESSION.setUser(SESSION.user, headers.authorization);
|
|
22
|
+
}
|
|
23
|
+
return { credentials: "same-origin", ...options, query, headers };
|
|
24
|
+
}
|
|
25
|
+
export async function useCsrfQuery(url, baseOptions) {
|
|
26
|
+
const { $csrfFetch } = useNuxtApp();
|
|
27
|
+
const { responseType, ...options } = await getQueryOptions(baseOptions);
|
|
28
|
+
return $csrfFetch(url, options);
|
|
29
|
+
}
|
|
30
|
+
export async function useQuery(url, baseOptions) {
|
|
31
|
+
const options = await getQueryOptions(baseOptions);
|
|
32
|
+
return $fetch(url, options);
|
|
33
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function useImagePath(path?: string, preset?: "avatar" | "small" | "medium" | "large"): string;
|
|
2
|
+
/**
|
|
3
|
+
* Return object with differing properties if any
|
|
4
|
+
*/
|
|
5
|
+
export declare function getValuesDiff<V extends Record<string, any>>(values: V, expectedValues: Partial<V>): Partial<V> | undefined;
|
|
6
|
+
export declare function useCreateError(message: string, statusCode?: number): import("nuxt/app").NuxtError<unknown>;
|
|
7
|
+
/**
|
|
8
|
+
* Append tracking information to external urls
|
|
9
|
+
*/
|
|
10
|
+
export declare function useUTMLink(link: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Attemp to reload image after a few seconds
|
|
13
|
+
*/
|
|
14
|
+
export declare function onImageError(event: Event, attemp?: number): string | undefined;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { isEqual } from "lodash-es";
|
|
2
|
+
import { createError, useAppStore, useInstanceStore } from "#imports";
|
|
3
|
+
export function useImagePath(path, preset = "avatar") {
|
|
4
|
+
if (!path || path === "/sample-loading.png") return "/sample-loading.png";
|
|
5
|
+
else if (path.startsWith("/api/media/images")) return path;
|
|
6
|
+
else if (path.startsWith("/firebase")) path = path.replace("/firebase", "/api/media/images");
|
|
7
|
+
else path = `/api/media/images/${path}/${preset}.webp`;
|
|
8
|
+
return `${path}?temp=${Date.now()}`;
|
|
9
|
+
}
|
|
10
|
+
export function getValuesDiff(values, expectedValues) {
|
|
11
|
+
const keysWithDifference = [];
|
|
12
|
+
const differentValues = {};
|
|
13
|
+
for (const k in expectedValues) {
|
|
14
|
+
if (!Object.hasOwn(expectedValues, k)) continue;
|
|
15
|
+
const expected = ![null, void 0, ""].includes(expectedValues[k]);
|
|
16
|
+
const provided = values[k] || values[k] === 0;
|
|
17
|
+
if (k in values || expected && !provided) {
|
|
18
|
+
const equal = isEqual(values[k], expectedValues[k]);
|
|
19
|
+
const emptyArray = isEqual(values[k] || [], expectedValues[k]);
|
|
20
|
+
if (equal || emptyArray) continue;
|
|
21
|
+
keysWithDifference.push(k);
|
|
22
|
+
differentValues[k] = values[k] ?? "";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (!keysWithDifference.length) return;
|
|
26
|
+
return differentValues;
|
|
27
|
+
}
|
|
28
|
+
export function useCreateError(message, statusCode = 500) {
|
|
29
|
+
return createError({ message, statusCode, fatal: true });
|
|
30
|
+
}
|
|
31
|
+
export function useUTMLink(link) {
|
|
32
|
+
const INSTANCE = useInstanceStore();
|
|
33
|
+
const { hostname } = new URL(INSTANCE.current?.url || "");
|
|
34
|
+
const url = new URL(link);
|
|
35
|
+
url.searchParams.append("utm_source", hostname);
|
|
36
|
+
url.searchParams.append("utm_content", "textlink");
|
|
37
|
+
return url.toString();
|
|
38
|
+
}
|
|
39
|
+
export function onImageError(event, attemp = 0) {
|
|
40
|
+
if (attemp >= 20) return;
|
|
41
|
+
const APP = useAppStore();
|
|
42
|
+
const img = event.target;
|
|
43
|
+
const [src] = img.src.split("?");
|
|
44
|
+
if (src.includes("/api/media/images/instances/")) {
|
|
45
|
+
const key = src.slice(18, src.lastIndexOf("/"));
|
|
46
|
+
const thumbnail = APP.thumbnails[key];
|
|
47
|
+
if (thumbnail) return img.src = thumbnail;
|
|
48
|
+
}
|
|
49
|
+
setTimeout(async () => {
|
|
50
|
+
try {
|
|
51
|
+
const now = Date.now();
|
|
52
|
+
const unchached = `${src}?t=${now}`;
|
|
53
|
+
const response = await fetch(src);
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
if (response.status === 503 || response.status === 404) {
|
|
56
|
+
return onImageError(event, attemp++);
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
img.src = unchached;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}, 1e3 * 5);
|
|
65
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { FieldValue, Timestamp } from "firebase-admin/firestore";
|
|
2
|
+
import type { ePaymentValidator } from "../../utils/enums.js";
|
|
3
|
+
export type FirebaseValues<T extends FirebaseData> = {
|
|
4
|
+
[K in keyof T]?: T[K] | FieldValue;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Extended firebase DocumentData
|
|
8
|
+
*
|
|
9
|
+
* @abstract
|
|
10
|
+
*/
|
|
11
|
+
export interface FirebaseData extends Record<string, any> {
|
|
12
|
+
/** @automated Creation date */
|
|
13
|
+
createdAt?: Timestamp;
|
|
14
|
+
/** @automated Last update date */
|
|
15
|
+
updatedAt?: Timestamp;
|
|
16
|
+
/**
|
|
17
|
+
* Lock document & prevent deletion
|
|
18
|
+
* A boolean or an array of reference paths locking the document
|
|
19
|
+
*
|
|
20
|
+
* @automated
|
|
21
|
+
*/
|
|
22
|
+
lock?: boolean | string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Price data
|
|
26
|
+
*
|
|
27
|
+
* @abstract
|
|
28
|
+
*/
|
|
29
|
+
export interface PriceData {
|
|
30
|
+
/** Full price */
|
|
31
|
+
price?: number;
|
|
32
|
+
/** base price (no iva) */
|
|
33
|
+
base?: number;
|
|
34
|
+
/** Iva price */
|
|
35
|
+
iva?: number;
|
|
36
|
+
/** @automated unique item ref */
|
|
37
|
+
reference?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Payment data
|
|
41
|
+
*
|
|
42
|
+
* @abstract
|
|
43
|
+
*/
|
|
44
|
+
export interface PaymentData extends PriceData {
|
|
45
|
+
/** @automated Integrity hash */
|
|
46
|
+
integrity?: string;
|
|
47
|
+
/** @automated Payment validation source */
|
|
48
|
+
validator?: ePaymentValidator;
|
|
49
|
+
/**
|
|
50
|
+
* Client has paid
|
|
51
|
+
* @automated Payment date
|
|
52
|
+
*/
|
|
53
|
+
paidAt?: false | Timestamp;
|
|
54
|
+
observations?: string;
|
|
55
|
+
oldObservations?: string;
|
|
56
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { DocumentReference } from "firebase-admin/firestore";
|
|
2
|
+
import type { FirebaseData } from "./base.js";
|
|
3
|
+
import type { LogData } from "./logs.js";
|
|
4
|
+
import type { UserData } from "./user.js";
|
|
5
|
+
/**
|
|
6
|
+
* Document can be modified by any user
|
|
7
|
+
*
|
|
8
|
+
* This data is used to keep track of the changes
|
|
9
|
+
*/
|
|
10
|
+
export interface SharedData extends FirebaseData {
|
|
11
|
+
createdByRef?: DocumentReference;
|
|
12
|
+
updatedByRef?: DocumentReference;
|
|
13
|
+
deletedByRef?: DocumentReference;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Root instance
|
|
17
|
+
* Stores data that is shared across all instances
|
|
18
|
+
*
|
|
19
|
+
* @collection instances
|
|
20
|
+
*/
|
|
21
|
+
export interface RootData extends InstanceData {
|
|
22
|
+
config?: InstanceData["config"] & {
|
|
23
|
+
/**
|
|
24
|
+
* IVA percentage
|
|
25
|
+
* Keep track of the IVA percentage
|
|
26
|
+
* @example 19
|
|
27
|
+
*/
|
|
28
|
+
iva?: number;
|
|
29
|
+
};
|
|
30
|
+
/** @example "Xamu" */
|
|
31
|
+
poweredBy?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* App instance
|
|
35
|
+
*
|
|
36
|
+
* @collection instances
|
|
37
|
+
*/
|
|
38
|
+
export interface InstanceData extends SharedData {
|
|
39
|
+
locationCity?: string;
|
|
40
|
+
locationState?: string;
|
|
41
|
+
locationCountry?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Canonical site url
|
|
44
|
+
*
|
|
45
|
+
* @example https://my-store.mydomain.com
|
|
46
|
+
* @automated
|
|
47
|
+
*/
|
|
48
|
+
url?: string;
|
|
49
|
+
config?: {
|
|
50
|
+
[key: string]: any;
|
|
51
|
+
/**
|
|
52
|
+
* When tenants are enabled, domains are required
|
|
53
|
+
*/
|
|
54
|
+
domains?: string[];
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Firebase log
|
|
59
|
+
*
|
|
60
|
+
* @collection instances/logs
|
|
61
|
+
*/
|
|
62
|
+
export interface InstanceLogData extends LogData, SharedData {
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Instance member
|
|
66
|
+
*
|
|
67
|
+
* @collection instances/members
|
|
68
|
+
*/
|
|
69
|
+
export interface InstanceMemberData extends SharedData {
|
|
70
|
+
userRef?: DocumentReference<UserData>;
|
|
71
|
+
/** Could be non existent */
|
|
72
|
+
rootMemberRef?: DocumentReference<InstanceMemberData>;
|
|
73
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FirebaseData } from "./base.js";
|
|
2
|
+
/** General log entity */
|
|
3
|
+
export interface LogData extends FirebaseData {
|
|
4
|
+
at?: string;
|
|
5
|
+
code?: string;
|
|
6
|
+
message?: string;
|
|
7
|
+
error?: string;
|
|
8
|
+
/** Additional log tracking metadata */
|
|
9
|
+
metadata?: any;
|
|
10
|
+
/**
|
|
11
|
+
* Internal logs, omit some automation
|
|
12
|
+
* @automated
|
|
13
|
+
*/
|
|
14
|
+
internal?: boolean;
|
|
15
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SharedData } from "./instance.js";
|
|
2
|
+
/**
|
|
3
|
+
* Firebase user
|
|
4
|
+
*
|
|
5
|
+
* @collection
|
|
6
|
+
*/
|
|
7
|
+
export interface UserData extends SharedData {
|
|
8
|
+
uid?: string;
|
|
9
|
+
photoURL?: string | null;
|
|
10
|
+
isAnonymous?: boolean | null;
|
|
11
|
+
name?: string | null;
|
|
12
|
+
email?: string | null;
|
|
13
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encrypts a given text using AES-256-CBC algorithm.
|
|
3
|
+
*
|
|
4
|
+
* This function takes in a text to be encrypted and an encryption key.
|
|
5
|
+
* It generates a random initialization vector (IV) and uses it along with the key to create a cipher.
|
|
6
|
+
* The text is then encrypted using the cipher and the encrypted text is concatenated with the IV.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} text - The text to be encrypted.
|
|
9
|
+
* @param {string} key - The encryption key.
|
|
10
|
+
* @returns {string} The encrypted text, concatenated with the initialization vector.
|
|
11
|
+
*/
|
|
12
|
+
export declare function encrypt(text: string, key: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Decrypts a given encrypted text using AES-256-CBC algorithm.
|
|
15
|
+
*
|
|
16
|
+
* This function takes in an encrypted text and an encryption key.
|
|
17
|
+
* It splits the encrypted text into the initialization vector (IV) and the actual encrypted text.
|
|
18
|
+
* It then uses the IV and the key to create a decipher and decrypts the text.
|
|
19
|
+
*
|
|
20
|
+
* @param {string} text - The encrypted text to be decrypted.
|
|
21
|
+
* @param {string} key - The encryption key.
|
|
22
|
+
* @returns {string} The decrypted text.
|
|
23
|
+
*/
|
|
24
|
+
export declare function decrypt(text: string, key: string): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
2
|
+
export function encrypt(text, key) {
|
|
3
|
+
const iv = randomBytes(16);
|
|
4
|
+
const cipher = createCipheriv("aes-256-cbc", Buffer.from(key.padEnd(32, "0")), iv);
|
|
5
|
+
let encrypted = cipher.update(text);
|
|
6
|
+
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
|
7
|
+
return iv.toString("hex") + ":" + encrypted.toString("hex");
|
|
8
|
+
}
|
|
9
|
+
export function decrypt(text, key) {
|
|
10
|
+
const parts = text.split(":");
|
|
11
|
+
const iv = Buffer.from(parts.shift(), "hex");
|
|
12
|
+
const encryptedText = Buffer.from(parts.join(":"), "hex");
|
|
13
|
+
const decipher = createDecipheriv("aes-256-cbc", Buffer.from(key.padEnd(32, "0")), iv);
|
|
14
|
+
let decrypted = decipher.update(encryptedText);
|
|
15
|
+
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
|
16
|
+
return decrypted.toString();
|
|
17
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare enum eIdDocumentType {
|
|
2
|
+
/** Cédula de ciudadanía */
|
|
3
|
+
CC = "CC",
|
|
4
|
+
/** Cédula de extranjería */
|
|
5
|
+
CE = "CE",
|
|
6
|
+
/** Pasaporte */
|
|
7
|
+
PA = "PA",
|
|
8
|
+
/** Tarjeta de identidad */
|
|
9
|
+
TI = "TI",
|
|
10
|
+
/** Numero de identificación tributario */
|
|
11
|
+
NIT = "NIT"
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Purchase validation source
|
|
15
|
+
*/
|
|
16
|
+
export declare enum ePaymentValidator {
|
|
17
|
+
/** Gateway did its job */
|
|
18
|
+
WEBHOOK = "WEBHOOK",
|
|
19
|
+
/** Timeout elapsep */
|
|
20
|
+
TIMEOUT_TASK = "TIMEOUT_TASK",
|
|
21
|
+
/** User returned from gateway */
|
|
22
|
+
TURNBACK = "TURNBACK",
|
|
23
|
+
/** Admin handled the charge */
|
|
24
|
+
ADMIN = "ADMIN"
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Cache control
|
|
28
|
+
*/
|
|
29
|
+
export declare enum eCacheControl {
|
|
30
|
+
NONE = "no-cache, no-store, must-revalidate",
|
|
31
|
+
/** Cache for a few minutes */
|
|
32
|
+
FREQUENT = "public, max-age=120, stale-while-revalidate=60",
|
|
33
|
+
/** Cache for an hour */
|
|
34
|
+
NORMAL = "public, max-age=3600, must-revalidate",
|
|
35
|
+
/** Cache for a month */
|
|
36
|
+
MIDTERM = "public, max-age=2592000, must-revalidate",
|
|
37
|
+
/** Cache for a year */
|
|
38
|
+
LONGTERM = "public, max-age=31536000, must-revalidate"
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export var eIdDocumentType = /* @__PURE__ */ ((eIdDocumentType2) => {
|
|
2
|
+
eIdDocumentType2["CC"] = "CC";
|
|
3
|
+
eIdDocumentType2["CE"] = "CE";
|
|
4
|
+
eIdDocumentType2["PA"] = "PA";
|
|
5
|
+
eIdDocumentType2["TI"] = "TI";
|
|
6
|
+
eIdDocumentType2["NIT"] = "NIT";
|
|
7
|
+
return eIdDocumentType2;
|
|
8
|
+
})(eIdDocumentType || {});
|
|
9
|
+
export var ePaymentValidator = /* @__PURE__ */ ((ePaymentValidator2) => {
|
|
10
|
+
ePaymentValidator2["WEBHOOK"] = "WEBHOOK";
|
|
11
|
+
ePaymentValidator2["TIMEOUT_TASK"] = "TIMEOUT_TASK";
|
|
12
|
+
ePaymentValidator2["TURNBACK"] = "TURNBACK";
|
|
13
|
+
ePaymentValidator2["ADMIN"] = "ADMIN";
|
|
14
|
+
return ePaymentValidator2;
|
|
15
|
+
})(ePaymentValidator || {});
|
|
16
|
+
export var eCacheControl = /* @__PURE__ */ ((eCacheControl2) => {
|
|
17
|
+
eCacheControl2["NONE"] = "no-cache, no-store, must-revalidate";
|
|
18
|
+
eCacheControl2["FREQUENT"] = "public, max-age=120, stale-while-revalidate=60";
|
|
19
|
+
eCacheControl2["NORMAL"] = "public, max-age=3600, must-revalidate";
|
|
20
|
+
eCacheControl2["MIDTERM"] = "public, max-age=2592000, must-revalidate";
|
|
21
|
+
eCacheControl2["LONGTERM"] = "public, max-age=31536000, must-revalidate";
|
|
22
|
+
return eCacheControl2;
|
|
23
|
+
})(eCacheControl || {});
|
|
24
|
+
export {};
|