@olinfo/quizms-firebase 4.0.1 → 4.1.1

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.
Files changed (68) hide show
  1. package/dist/functions.d.ts +2 -11
  2. package/dist/functions.js +2 -2
  3. package/dist/package.json.js +1 -1
  4. package/dist/src/cli/files/functions-index.js +4 -4
  5. package/dist/src/cli/files/functions-index.js.map +1 -1
  6. package/dist/src/cli/import.js +85 -96
  7. package/dist/src/cli/import.js.map +1 -1
  8. package/dist/src/cli/init.js +8 -8
  9. package/dist/src/cli/init.js.map +1 -1
  10. package/dist/src/cli/update-scores.js +21 -32
  11. package/dist/src/cli/update-scores.js.map +1 -1
  12. package/dist/src/cli/utils/collection.js +20 -18
  13. package/dist/src/cli/utils/collection.js.map +1 -1
  14. package/dist/src/cli/utils/converters-admin.js +31 -32
  15. package/dist/src/cli/utils/converters-admin.js.map +1 -1
  16. package/dist/src/cli/utils/region-finder.js +6 -5
  17. package/dist/src/cli/utils/region-finder.js.map +1 -1
  18. package/dist/src/cli/utils/storage.js +26 -35
  19. package/dist/src/cli/utils/storage.js.map +1 -1
  20. package/dist/src/cli/utils/users.js +13 -12
  21. package/dist/src/cli/utils/users.js.map +1 -1
  22. package/dist/src/functions/api/admin.js +25 -10
  23. package/dist/src/functions/api/admin.js.map +1 -1
  24. package/dist/src/functions/api/index.js +26 -37
  25. package/dist/src/functions/api/index.js.map +1 -1
  26. package/dist/src/functions/api/queries.js +24 -25
  27. package/dist/src/functions/api/queries.js.map +1 -1
  28. package/dist/src/functions/api/student.js +62 -72
  29. package/dist/src/functions/api/student.js.map +1 -1
  30. package/dist/src/functions/api/teacher.js +104 -111
  31. package/dist/src/functions/api/teacher.js.map +1 -1
  32. package/dist/src/functions/api/trpc.js +18 -0
  33. package/dist/src/functions/api/trpc.js.map +1 -0
  34. package/dist/src/functions/submissions.js +1 -1
  35. package/dist/src/functions/submissions.js.map +1 -1
  36. package/dist/src/models/user.js +2 -2
  37. package/dist/src/models/user.js.map +1 -1
  38. package/dist/src/models/website.js +1 -1
  39. package/dist/src/models/website.js.map +1 -1
  40. package/dist/src/vite/preset.js +3 -4
  41. package/dist/src/vite/preset.js.map +1 -1
  42. package/dist/src/web/admin/announcements.js +9 -10
  43. package/dist/src/web/admin/announcements.js.map +1 -1
  44. package/dist/src/web/admin/school-table.js +7 -8
  45. package/dist/src/web/admin/school-table.js.map +1 -1
  46. package/dist/src/web/common/api.js +32 -35
  47. package/dist/src/web/common/api.js.map +1 -1
  48. package/dist/src/web/common/converters.js +35 -36
  49. package/dist/src/web/common/converters.js.map +1 -1
  50. package/dist/src/web/common/token-login.js +11 -11
  51. package/dist/src/web/common/token-login.js.map +1 -1
  52. package/dist/src/web/entry/admin.js +5 -7
  53. package/dist/src/web/entry/admin.js.map +1 -1
  54. package/dist/src/web/entry/student-restoring.js +18 -20
  55. package/dist/src/web/entry/student-restoring.js.map +1 -1
  56. package/dist/src/web/entry/student.js +70 -76
  57. package/dist/src/web/entry/student.js.map +1 -1
  58. package/dist/src/web/entry/teacher.js +68 -68
  59. package/dist/src/web/entry/teacher.js.map +1 -1
  60. package/dist/src/web/hooks/collection.js +29 -30
  61. package/dist/src/web/hooks/collection.js.map +1 -1
  62. package/dist/src/web/hooks/document.js +35 -36
  63. package/dist/src/web/hooks/document.js.map +1 -1
  64. package/dist/src/web/hooks/subscription.js +26 -22
  65. package/dist/src/web/hooks/subscription.js.map +1 -1
  66. package/package.json +29 -25
  67. package/dist/src/functions/api/schema.js +0 -42
  68. package/dist/src/functions/api/schema.js.map +0 -1
@@ -11,56 +11,55 @@ const d = {
11
11
  rollbackOnError: !0,
12
12
  populateCache: !0
13
13
  };
14
- function j(s, t, r) {
15
- const e = E(), { showBoundary: a } = R(), c = g(e, s).withConverter(t), m = $(e, s, t, r), b = {
16
- revalidateIfStale: !r?.subscribe,
17
- revalidateOnFocus: !r?.subscribe,
18
- revalidateOnMount: !r?.subscribe,
19
- revalidateOnReconnect: !r?.subscribe,
14
+ function j(a, t, r) {
15
+ const e = E(), { showBoundary: s } = R(), i = g(e, a).withConverter(t), m = $(e, a, t, r), p = {
16
+ revalidateIfStale: !1,
17
+ revalidateOnFocus: !1,
18
+ revalidateOnMount: !1,
19
+ revalidateOnReconnect: !1,
20
20
  suspense: !0
21
- }, f = `${s}?${JSON.stringify(r)}`, { data: y, mutate: o } = q(f, () => D(m), b), h = C(
22
- (i) => x(c, i, o, r),
23
- [c, o, r]
21
+ }, f = `${a}?${JSON.stringify(r)}`, { data: y, mutate: n } = q(f, () => D(m), p), b = C(
22
+ (o) => x(i, o, n, r),
23
+ [i, n, r]
24
24
  );
25
25
  return w(
26
26
  f,
27
- (i) => {
28
- if (!r?.subscribe) return;
29
- const p = B(
27
+ (o) => {
28
+ const h = B(
30
29
  m,
31
- (u) => {
30
+ (c) => {
32
31
  try {
33
- i(u.docs.map((n) => n.data()));
34
- } catch (n) {
35
- a(n);
32
+ o(c.docs.map((u) => u.data()));
33
+ } catch (u) {
34
+ s(u);
36
35
  }
37
36
  },
38
- (u) => a(u)
37
+ (c) => s(c)
39
38
  );
40
- return () => p();
39
+ return () => h();
41
40
  },
42
- (i) => o(i, d)
43
- ), [y, h];
41
+ (o) => n(o, d)
42
+ ), [y, b];
44
43
  }
45
- async function x(s, t, r, e) {
44
+ async function x(a, t, r, e) {
46
45
  await r(
47
- async (a) => {
48
- const c = O(s, t.id);
49
- return await S(c, t), l(a, t, e);
46
+ async (s) => {
47
+ const i = O(a, t.id);
48
+ return await S(i, t), l(s, t, e);
50
49
  },
51
50
  {
52
51
  ...d,
53
- optimisticData: (a) => l(a, t, e)
52
+ optimisticData: (s) => l(s, t, e)
54
53
  }
55
54
  );
56
55
  }
57
- function l(s, t, r) {
58
- if (!s) return [t];
59
- let e = s.filter((a) => t.id !== a.id);
56
+ function l(a, t, r) {
57
+ if (!a) return [t];
58
+ let e = a.filter((s) => t.id !== s.id);
60
59
  return e.push(t), e = k(e, [r?.orderBy ?? "id"]), r?.limit && (e = e.slice(0, r.limit)), e;
61
60
  }
62
- async function D(s) {
63
- return (await v(s)).docs.map((r) => r.data({ serverTimestamps: "estimate" }));
61
+ async function D(a) {
62
+ return (await v(a)).docs.map((r) => r.data({ serverTimestamps: "estimate" }));
64
63
  }
65
64
  export {
66
65
  j as useCollection
@@ -1 +1 @@
1
- {"version":3,"file":"collection.js","sources":["../../../../src/web/hooks/collection.ts"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport {\n type CollectionReference,\n collection,\n doc,\n type FirestoreDataConverter,\n getDocs,\n onSnapshot,\n type Query,\n setDoc,\n} from \"firebase/firestore\";\nimport { sortBy } from \"lodash-es\";\nimport { useErrorBoundary } from \"react-error-boundary\";\nimport useSWR, { type KeyedMutator, type MutatorOptions, type SWRConfiguration } from \"swr\";\n\nimport { useDb } from \"~/web/common/base-login\";\nimport query, { type QueryOption } from \"~/web/common/query\";\n\nimport { useSubscriptionListener } from \"./subscription\";\n\nconst mutationConfig: MutatorOptions = {\n revalidate: false,\n rollbackOnError: true,\n populateCache: true,\n};\n\ntype CollectionOptions<T> = QueryOption<T> & {\n subscribe?: boolean;\n};\n\nexport function useCollection<T extends { id: string }>(\n path: string,\n converter: FirestoreDataConverter<T>,\n options?: CollectionOptions<T>,\n) {\n const db = useDb();\n const { showBoundary } = useErrorBoundary();\n\n const ref = collection(db, path).withConverter(converter);\n const q = query(db, path, converter, options);\n\n const swrConfig: SWRConfiguration = {\n revalidateIfStale: !options?.subscribe,\n revalidateOnFocus: !options?.subscribe,\n revalidateOnMount: !options?.subscribe,\n revalidateOnReconnect: !options?.subscribe,\n suspense: true,\n };\n\n const key = `${path}?${JSON.stringify(options)}`;\n const { data, mutate } = useSWR<T[]>(key, () => fetcher(q), swrConfig);\n\n const setData = useCallback(\n (newDoc: T) => setDocument(ref, newDoc, mutate, options),\n [ref, mutate, options],\n );\n\n useSubscriptionListener<T[]>(\n key,\n (setData) => {\n if (!options?.subscribe) return;\n const unsubscribe = onSnapshot(\n q,\n (snap) => {\n try {\n setData(snap.docs.map((doc) => doc.data()));\n } catch (err) {\n showBoundary(err);\n }\n },\n (error) => showBoundary(error),\n );\n return () => unsubscribe();\n },\n (data) => mutate(data, mutationConfig),\n );\n\n return [data as T[], setData] as const;\n}\n\nasync function setDocument<T extends { id: string }>(\n ref: CollectionReference<T>,\n newDoc: T,\n mutator: KeyedMutator<T[]>,\n options?: CollectionOptions<T>,\n): Promise<void> {\n await mutator(\n async (prev) => {\n const docRef = doc(ref, newDoc.id);\n await setDoc(docRef, newDoc);\n return merge(prev, newDoc, options);\n },\n {\n ...mutationConfig,\n optimisticData: (prev) => merge(prev, newDoc, options),\n },\n );\n}\n\nfunction merge<T extends { id: string }>(\n prev: T[] | undefined,\n newDoc: T,\n options?: CollectionOptions<T>,\n) {\n if (!prev) return [newDoc];\n let coll = prev.filter((doc) => newDoc.id !== doc.id);\n coll.push(newDoc);\n coll = sortBy(coll, [options?.orderBy ?? \"id\"]);\n if (options?.limit) coll = coll.slice(0, options.limit);\n return coll;\n}\n\nasync function fetcher<T>(ref: Query<T>) {\n const snapshot = await getDocs(ref);\n return snapshot.docs.map((doc) => doc.data({ serverTimestamps: \"estimate\" }));\n}\n"],"names":["mutationConfig","useCollection","path","converter","options","db","useDb","showBoundary","useErrorBoundary","ref","collection","q","query","swrConfig","key","data","mutate","useSWR","fetcher","setData","useCallback","newDoc","setDocument","useSubscriptionListener","unsubscribe","onSnapshot","snap","doc","err","error","mutator","prev","docRef","setDoc","merge","coll","sortBy","getDocs"],"mappings":";;;;;;;;AAqBA,MAAMA,IAAiC;AAAA,EACrC,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,eAAe;AACjB;AAMO,SAASC,EACdC,GACAC,GACAC,GACA;AACA,QAAMC,IAAKC,EAAA,GACL,EAAE,cAAAC,EAAA,IAAiBC,EAAA,GAEnBC,IAAMC,EAAWL,GAAIH,CAAI,EAAE,cAAcC,CAAS,GAClDQ,IAAIC,EAAMP,GAAIH,GAAMC,GAAWC,CAAO,GAEtCS,IAA8B;AAAA,IAClC,mBAAmB,CAACT,GAAS;AAAA,IAC7B,mBAAmB,CAACA,GAAS;AAAA,IAC7B,mBAAmB,CAACA,GAAS;AAAA,IAC7B,uBAAuB,CAACA,GAAS;AAAA,IACjC,UAAU;AAAA,EAAA,GAGNU,IAAM,GAAGZ,CAAI,IAAI,KAAK,UAAUE,CAAO,CAAC,IACxC,EAAE,MAAAW,GAAM,QAAAC,EAAA,IAAWC,EAAYH,GAAK,MAAMI,EAAQP,CAAC,GAAGE,CAAS,GAE/DM,IAAUC;AAAA,IACd,CAACC,MAAcC,EAAYb,GAAKY,GAAQL,GAAQZ,CAAO;AAAA,IACvD,CAACK,GAAKO,GAAQZ,CAAO;AAAA,EAAA;AAGvB,SAAAmB;AAAA,IACET;AAAA,IACA,CAACK,MAAY;AACX,UAAI,CAACf,GAAS,UAAW;AACzB,YAAMoB,IAAcC;AAAA,QAClBd;AAAA,QACA,CAACe,MAAS;AACR,cAAI;AACFP,YAAAA,EAAQO,EAAK,KAAK,IAAI,CAACC,MAAQA,EAAI,KAAA,CAAM,CAAC;AAAA,UAC5C,SAASC,GAAK;AACZ,YAAArB,EAAaqB,CAAG;AAAA,UAClB;AAAA,QACF;AAAA,QACA,CAACC,MAAUtB,EAAasB,CAAK;AAAA,MAAA;AAE/B,aAAO,MAAML,EAAA;AAAA,IACf;AAAA,IACA,CAACT,MAASC,EAAOD,GAAMf,CAAc;AAAA,EAAA,GAGhC,CAACe,GAAaI,CAAO;AAC9B;AAEA,eAAeG,EACbb,GACAY,GACAS,GACA1B,GACe;AACf,QAAM0B;AAAA,IACJ,OAAOC,MAAS;AACd,YAAMC,IAASL,EAAIlB,GAAKY,EAAO,EAAE;AACjC,mBAAMY,EAAOD,GAAQX,CAAM,GACpBa,EAAMH,GAAMV,GAAQjB,CAAO;AAAA,IACpC;AAAA,IACA;AAAA,MACE,GAAGJ;AAAA,MACH,gBAAgB,CAAC+B,MAASG,EAAMH,GAAMV,GAAQjB,CAAO;AAAA,IAAA;AAAA,EACvD;AAEJ;AAEA,SAAS8B,EACPH,GACAV,GACAjB,GACA;AACA,MAAI,CAAC2B,EAAM,QAAO,CAACV,CAAM;AACzB,MAAIc,IAAOJ,EAAK,OAAO,CAACJ,MAAQN,EAAO,OAAOM,EAAI,EAAE;AACpD,SAAAQ,EAAK,KAAKd,CAAM,GAChBc,IAAOC,EAAOD,GAAM,CAAC/B,GAAS,WAAW,IAAI,CAAC,GAC1CA,GAAS,UAAO+B,IAAOA,EAAK,MAAM,GAAG/B,EAAQ,KAAK,IAC/C+B;AACT;AAEA,eAAejB,EAAWT,GAAe;AAEvC,UADiB,MAAM4B,EAAQ5B,CAAG,GAClB,KAAK,IAAI,CAACkB,MAAQA,EAAI,KAAK,EAAE,kBAAkB,WAAA,CAAY,CAAC;AAC9E;"}
1
+ {"version":3,"file":"collection.js","sources":["../../../../src/web/hooks/collection.ts"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport {\n type CollectionReference,\n collection,\n doc,\n type FirestoreDataConverter,\n getDocs,\n onSnapshot,\n type Query,\n setDoc,\n} from \"firebase/firestore\";\nimport { sortBy } from \"lodash-es\";\nimport { useErrorBoundary } from \"react-error-boundary\";\nimport useSWR, { type KeyedMutator, type MutatorOptions, type SWRConfiguration } from \"swr\";\n\nimport { useDb } from \"~/web/common/base-login\";\nimport query, { type QueryOption } from \"~/web/common/query\";\n\nimport { useSubscriptionListener } from \"./subscription\";\n\nconst mutationConfig: MutatorOptions = {\n revalidate: false,\n rollbackOnError: true,\n populateCache: true,\n};\n\nexport function useCollection<T extends { id: string }>(\n path: string,\n converter: FirestoreDataConverter<T>,\n options?: QueryOption<T>,\n) {\n const db = useDb();\n const { showBoundary } = useErrorBoundary();\n\n const ref = collection(db, path).withConverter(converter);\n const q = query(db, path, converter, options);\n\n const swrConfig: SWRConfiguration = {\n revalidateIfStale: false,\n revalidateOnFocus: false,\n revalidateOnMount: false,\n revalidateOnReconnect: false,\n suspense: true,\n };\n\n const key = `${path}?${JSON.stringify(options)}`;\n const { data, mutate } = useSWR<T[]>(key, () => fetcher(q), swrConfig);\n\n const setData = useCallback(\n (newDoc: T) => setDocument(ref, newDoc, mutate, options),\n [ref, mutate, options],\n );\n\n useSubscriptionListener<T[]>(\n key,\n (setData) => {\n const unsubscribe = onSnapshot(\n q,\n (snap) => {\n try {\n setData(snap.docs.map((doc) => doc.data()));\n } catch (err) {\n showBoundary(err as Error);\n }\n },\n (error) => showBoundary(error),\n );\n return () => unsubscribe();\n },\n (data) => mutate(data, mutationConfig),\n );\n\n return [data as T[], setData] as const;\n}\n\nasync function setDocument<T extends { id: string }>(\n ref: CollectionReference<T>,\n newDoc: T,\n mutator: KeyedMutator<T[]>,\n options?: QueryOption<T>,\n): Promise<void> {\n await mutator(\n async (prev) => {\n const docRef = doc(ref, newDoc.id);\n await setDoc(docRef, newDoc);\n return merge(prev, newDoc, options);\n },\n {\n ...mutationConfig,\n optimisticData: (prev) => merge(prev, newDoc, options),\n },\n );\n}\n\nfunction merge<T extends { id: string }>(\n prev: T[] | undefined,\n newDoc: T,\n options?: QueryOption<T>,\n) {\n if (!prev) return [newDoc];\n let coll = prev.filter((doc) => newDoc.id !== doc.id);\n coll.push(newDoc);\n coll = sortBy(coll, [options?.orderBy ?? \"id\"]);\n if (options?.limit) coll = coll.slice(0, options.limit);\n return coll;\n}\n\nasync function fetcher<T>(ref: Query<T>) {\n const snapshot = await getDocs(ref);\n return snapshot.docs.map((doc) => doc.data({ serverTimestamps: \"estimate\" }));\n}\n"],"names":["mutationConfig","useCollection","path","converter","options","db","useDb","showBoundary","useErrorBoundary","ref","collection","q","query","swrConfig","key","data","mutate","useSWR","fetcher","setData","useCallback","newDoc","setDocument","useSubscriptionListener","unsubscribe","onSnapshot","snap","doc","err","error","mutator","prev","docRef","setDoc","merge","coll","sortBy","getDocs"],"mappings":";;;;;;;;AAqBA,MAAMA,IAAiC;AAAA,EACrC,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,eAAe;AACjB;AAEO,SAASC,EACdC,GACAC,GACAC,GACA;AACA,QAAMC,IAAKC,EAAA,GACL,EAAE,cAAAC,EAAA,IAAiBC,EAAA,GAEnBC,IAAMC,EAAWL,GAAIH,CAAI,EAAE,cAAcC,CAAS,GAClDQ,IAAIC,EAAMP,GAAIH,GAAMC,GAAWC,CAAO,GAEtCS,IAA8B;AAAA,IAClC,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,UAAU;AAAA,EAAA,GAGNC,IAAM,GAAGZ,CAAI,IAAI,KAAK,UAAUE,CAAO,CAAC,IACxC,EAAE,MAAAW,GAAM,QAAAC,EAAA,IAAWC,EAAYH,GAAK,MAAMI,EAAQP,CAAC,GAAGE,CAAS,GAE/DM,IAAUC;AAAA,IACd,CAACC,MAAcC,EAAYb,GAAKY,GAAQL,GAAQZ,CAAO;AAAA,IACvD,CAACK,GAAKO,GAAQZ,CAAO;AAAA,EAAA;AAGvB,SAAAmB;AAAA,IACET;AAAA,IACA,CAACK,MAAY;AACX,YAAMK,IAAcC;AAAA,QAClBd;AAAA,QACA,CAACe,MAAS;AACR,cAAI;AACFP,YAAAA,EAAQO,EAAK,KAAK,IAAI,CAACC,MAAQA,EAAI,KAAA,CAAM,CAAC;AAAA,UAC5C,SAASC,GAAK;AACZ,YAAArB,EAAaqB,CAAY;AAAA,UAC3B;AAAA,QACF;AAAA,QACA,CAACC,MAAUtB,EAAasB,CAAK;AAAA,MAAA;AAE/B,aAAO,MAAML,EAAA;AAAA,IACf;AAAA,IACA,CAACT,MAASC,EAAOD,GAAMf,CAAc;AAAA,EAAA,GAGhC,CAACe,GAAaI,CAAO;AAC9B;AAEA,eAAeG,EACbb,GACAY,GACAS,GACA1B,GACe;AACf,QAAM0B;AAAA,IACJ,OAAOC,MAAS;AACd,YAAMC,IAASL,EAAIlB,GAAKY,EAAO,EAAE;AACjC,mBAAMY,EAAOD,GAAQX,CAAM,GACpBa,EAAMH,GAAMV,GAAQjB,CAAO;AAAA,IACpC;AAAA,IACA;AAAA,MACE,GAAGJ;AAAA,MACH,gBAAgB,CAAC+B,MAASG,EAAMH,GAAMV,GAAQjB,CAAO;AAAA,IAAA;AAAA,EACvD;AAEJ;AAEA,SAAS8B,EACPH,GACAV,GACAjB,GACA;AACA,MAAI,CAAC2B,EAAM,QAAO,CAACV,CAAM;AACzB,MAAIc,IAAOJ,EAAK,OAAO,CAACJ,MAAQN,EAAO,OAAOM,EAAI,EAAE;AACpD,SAAAQ,EAAK,KAAKd,CAAM,GAChBc,IAAOC,EAAOD,GAAM,CAAC/B,GAAS,WAAW,IAAI,CAAC,GAC1CA,GAAS,UAAO+B,IAAOA,EAAK,MAAM,GAAG/B,EAAQ,KAAK,IAC/C+B;AACT;AAEA,eAAejB,EAAWT,GAAe;AAEvC,UADiB,MAAM4B,EAAQ5B,CAAG,GAClB,KAAK,IAAI,CAACkB,MAAQA,EAAI,KAAK,EAAE,kBAAkB,WAAA,CAAY,CAAC;AAC9E;"}
@@ -1,61 +1,60 @@
1
- import { useCallback as v } from "react";
2
- import { doc as y, onSnapshot as D, getDoc as w, setDoc as O } from "firebase/firestore";
3
- import { useErrorBoundary as C } from "react-error-boundary";
4
- import S from "swr";
5
- import { useDb as g } from "../common/base-login.js";
6
- import { useSubscriptionListener as $ } from "./subscription.js";
7
- const f = {
1
+ import { useCallback as h } from "react";
2
+ import { doc as v, onSnapshot as D, getDoc as b, setDoc as w } from "firebase/firestore";
3
+ import { useErrorBoundary as y } from "react-error-boundary";
4
+ import C from "swr";
5
+ import { useDb as O } from "../common/base-login.js";
6
+ import { useSubscriptionListener as S } from "./subscription.js";
7
+ const c = {
8
8
  revalidate: !1,
9
9
  rollbackOnError: !0,
10
10
  populateCache: !0
11
11
  };
12
- function M(r, t, s, e) {
13
- const [o, u] = k(r, t, s, e);
14
- if (!o) throw new Error(`Document ${r}/${t} not found`);
15
- return [o, u];
12
+ function L(e, t, o) {
13
+ const [n, s] = g(e, t, o);
14
+ if (!n) throw new Error(`Document ${e}/${t} not found`);
15
+ return [n, s];
16
16
  }
17
- function k(r, t, s, e) {
18
- const o = g(), { showBoundary: u } = C(), n = y(o, r, t).withConverter(s), b = {
19
- revalidateIfStale: !e?.subscribe,
20
- revalidateOnFocus: !e?.subscribe,
21
- revalidateOnMount: !e?.subscribe,
22
- revalidateOnReconnect: !e?.subscribe,
17
+ function g(e, t, o) {
18
+ const n = O(), { showBoundary: s } = y(), r = v(n, e, t).withConverter(o), f = {
19
+ revalidateIfStale: !1,
20
+ revalidateOnFocus: !1,
21
+ revalidateOnMount: !1,
22
+ revalidateOnReconnect: !1,
23
23
  suspense: !0
24
- }, m = `${n.path}?${JSON.stringify(e)}`, { data: d, mutate: c } = S(m, () => x(n), b);
25
- $(
26
- m,
24
+ }, { data: m, mutate: u } = C(r.path, () => k(r), f);
25
+ S(
26
+ r.path,
27
27
  (a) => {
28
- if (!e?.subscribe) return;
29
28
  const p = D(
30
- n,
29
+ r,
31
30
  (i) => {
32
31
  try {
33
32
  a([i.data()]);
34
- } catch (h) {
35
- u(h);
33
+ } catch (d) {
34
+ s(d);
36
35
  }
37
36
  },
38
- (i) => u(i)
37
+ (i) => s(i)
39
38
  );
40
39
  return () => p();
41
40
  },
42
- (a) => c(a, f)
41
+ (a) => u(a, c)
43
42
  );
44
- const l = v((a) => E(n, a, c), [c, n]);
45
- return [d[0], l];
43
+ const l = h((a) => E(r, a, u), [u, r]);
44
+ return [m[0], l];
46
45
  }
47
- async function E(r, t, s) {
48
- await s(
49
- async () => (await O(r, t), [t]),
50
- { ...f, optimisticData: [t] }
46
+ async function E(e, t, o) {
47
+ await o(
48
+ async () => (await w(e, t), [t]),
49
+ { ...c, optimisticData: [t] }
51
50
  );
52
51
  }
53
- async function x(r) {
54
- const t = await w(r);
52
+ async function k(e) {
53
+ const t = await b(e);
55
54
  return t.exists() ? [t.data({ serverTimestamps: "estimate" })] : [void 0];
56
55
  }
57
56
  export {
58
- M as useDocument,
59
- k as useDocumentOptional
57
+ L as useDocument,
58
+ g as useDocumentOptional
60
59
  };
61
60
  //# sourceMappingURL=document.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"document.js","sources":["../../../../src/web/hooks/document.ts"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport {\n type DocumentReference,\n doc,\n type FirestoreDataConverter,\n getDoc,\n onSnapshot,\n setDoc,\n} from \"firebase/firestore\";\nimport { useErrorBoundary } from \"react-error-boundary\";\nimport useSWR, { type KeyedMutator, type MutatorOptions, type SWRConfiguration } from \"swr\";\n\nimport { useDb } from \"~/web/common/base-login\";\n\nimport { useSubscriptionListener } from \"./subscription\";\n\nconst mutationConfig: MutatorOptions = {\n revalidate: false,\n rollbackOnError: true,\n populateCache: true,\n};\n\ntype Options = {\n subscribe?: boolean;\n};\n\nexport function useDocument<T>(\n path: string,\n id: string,\n converter: FirestoreDataConverter<T>,\n options?: Options,\n) {\n const [data, setData] = useDocumentOptional<T>(path, id, converter, options);\n if (!data) throw new Error(`Document ${path}/${id} not found`);\n return [data, setData] as const;\n}\n\nexport function useDocumentOptional<T>(\n path: string,\n id: string,\n converter: FirestoreDataConverter<T>,\n options?: Options,\n) {\n const db = useDb();\n const { showBoundary } = useErrorBoundary();\n\n const ref = doc(db, path, id).withConverter(converter);\n\n const swrConfig: SWRConfiguration = {\n revalidateIfStale: !options?.subscribe,\n revalidateOnFocus: !options?.subscribe,\n revalidateOnMount: !options?.subscribe,\n revalidateOnReconnect: !options?.subscribe,\n suspense: true,\n };\n\n const key = `${ref.path}?${JSON.stringify(options)}`;\n const { data, mutate } = useSWR<[T?]>(key, () => fetcher(ref), swrConfig);\n\n useSubscriptionListener<[T?]>(\n key,\n (setData) => {\n if (!options?.subscribe) return;\n const unsubscribe = onSnapshot(\n ref,\n (snap) => {\n try {\n setData([snap.data()]);\n } catch (err) {\n showBoundary(err);\n }\n },\n (error) => showBoundary(error),\n );\n return () => unsubscribe();\n },\n (data) => mutate(data, mutationConfig),\n );\n\n const setData = useCallback((newData: T) => setDocument<T>(ref, newData, mutate), [mutate, ref]);\n return [data![0], setData] as const;\n}\n\nasync function setDocument<T>(ref: DocumentReference<T>, newDoc: T, mutator: KeyedMutator<[T?]>) {\n await mutator(\n async () => {\n await setDoc(ref, newDoc);\n return [newDoc];\n },\n { ...mutationConfig, optimisticData: [newDoc] },\n );\n}\n\nasync function fetcher<T>(ref: DocumentReference<T>): Promise<[T?]> {\n const snapshot = await getDoc(ref);\n if (!snapshot.exists()) {\n return [undefined];\n }\n return [snapshot.data({ serverTimestamps: \"estimate\" })];\n}\n"],"names":["mutationConfig","useDocument","path","id","converter","options","data","setData","useDocumentOptional","db","useDb","showBoundary","useErrorBoundary","ref","doc","swrConfig","key","mutate","useSWR","fetcher","useSubscriptionListener","unsubscribe","onSnapshot","snap","err","error","useCallback","newData","setDocument","newDoc","mutator","setDoc","snapshot","getDoc"],"mappings":";;;;;;AAiBA,MAAMA,IAAiC;AAAA,EACrC,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,eAAe;AACjB;AAMO,SAASC,EACdC,GACAC,GACAC,GACAC,GACA;AACA,QAAM,CAACC,GAAMC,CAAO,IAAIC,EAAuBN,GAAMC,GAAIC,GAAWC,CAAO;AAC3E,MAAI,CAACC,EAAM,OAAM,IAAI,MAAM,YAAYJ,CAAI,IAAIC,CAAE,YAAY;AAC7D,SAAO,CAACG,GAAMC,CAAO;AACvB;AAEO,SAASC,EACdN,GACAC,GACAC,GACAC,GACA;AACA,QAAMI,IAAKC,EAAA,GACL,EAAE,cAAAC,EAAA,IAAiBC,EAAA,GAEnBC,IAAMC,EAAIL,GAAIP,GAAMC,CAAE,EAAE,cAAcC,CAAS,GAE/CW,IAA8B;AAAA,IAClC,mBAAmB,CAACV,GAAS;AAAA,IAC7B,mBAAmB,CAACA,GAAS;AAAA,IAC7B,mBAAmB,CAACA,GAAS;AAAA,IAC7B,uBAAuB,CAACA,GAAS;AAAA,IACjC,UAAU;AAAA,EAAA,GAGNW,IAAM,GAAGH,EAAI,IAAI,IAAI,KAAK,UAAUR,CAAO,CAAC,IAC5C,EAAE,MAAAC,GAAM,QAAAW,EAAA,IAAWC,EAAaF,GAAK,MAAMG,EAAQN,CAAG,GAAGE,CAAS;AAExE,EAAAK;AAAA,IACEJ;AAAA,IACA,CAACT,MAAY;AACX,UAAI,CAACF,GAAS,UAAW;AACzB,YAAMgB,IAAcC;AAAA,QAClBT;AAAA,QACA,CAACU,MAAS;AACR,cAAI;AACFhB,YAAAA,EAAQ,CAACgB,EAAK,KAAA,CAAM,CAAC;AAAA,UACvB,SAASC,GAAK;AACZ,YAAAb,EAAaa,CAAG;AAAA,UAClB;AAAA,QACF;AAAA,QACA,CAACC,MAAUd,EAAac,CAAK;AAAA,MAAA;AAE/B,aAAO,MAAMJ,EAAA;AAAA,IACf;AAAA,IACA,CAACf,MAASW,EAAOX,GAAMN,CAAc;AAAA,EAAA;AAGvC,QAAMO,IAAUmB,EAAY,CAACC,MAAeC,EAAef,GAAKc,GAASV,CAAM,GAAG,CAACA,GAAQJ,CAAG,CAAC;AAC/F,SAAO,CAACP,EAAM,CAAC,GAAGC,CAAO;AAC3B;AAEA,eAAeqB,EAAef,GAA2BgB,GAAWC,GAA6B;AAC/F,QAAMA;AAAA,IACJ,aACE,MAAMC,EAAOlB,GAAKgB,CAAM,GACjB,CAACA,CAAM;AAAA,IAEhB,EAAE,GAAG7B,GAAgB,gBAAgB,CAAC6B,CAAM,EAAA;AAAA,EAAE;AAElD;AAEA,eAAeV,EAAWN,GAA0C;AAClE,QAAMmB,IAAW,MAAMC,EAAOpB,CAAG;AACjC,SAAKmB,EAAS,WAGP,CAACA,EAAS,KAAK,EAAE,kBAAkB,WAAA,CAAY,CAAC,IAF9C,CAAC,MAAS;AAGrB;"}
1
+ {"version":3,"file":"document.js","sources":["../../../../src/web/hooks/document.ts"],"sourcesContent":["import { useCallback } from \"react\";\n\nimport {\n type DocumentReference,\n doc,\n type FirestoreDataConverter,\n getDoc,\n onSnapshot,\n setDoc,\n} from \"firebase/firestore\";\nimport { useErrorBoundary } from \"react-error-boundary\";\nimport useSWR, { type KeyedMutator, type MutatorOptions, type SWRConfiguration } from \"swr\";\n\nimport { useDb } from \"~/web/common/base-login\";\n\nimport { useSubscriptionListener } from \"./subscription\";\n\nconst mutationConfig: MutatorOptions = {\n revalidate: false,\n rollbackOnError: true,\n populateCache: true,\n};\n\nexport function useDocument<T>(path: string, id: string, converter: FirestoreDataConverter<T>) {\n const [data, setData] = useDocumentOptional<T>(path, id, converter);\n if (!data) throw new Error(`Document ${path}/${id} not found`);\n return [data, setData] as const;\n}\n\nexport function useDocumentOptional<T>(\n path: string,\n id: string,\n converter: FirestoreDataConverter<T>,\n) {\n const db = useDb();\n const { showBoundary } = useErrorBoundary();\n\n const ref = doc(db, path, id).withConverter(converter);\n\n const swrConfig: SWRConfiguration = {\n revalidateIfStale: false,\n revalidateOnFocus: false,\n revalidateOnMount: false,\n revalidateOnReconnect: false,\n suspense: true,\n };\n\n const { data, mutate } = useSWR<[T?]>(ref.path, () => fetcher(ref), swrConfig);\n\n useSubscriptionListener<[T?]>(\n ref.path,\n (setData) => {\n const unsubscribe = onSnapshot(\n ref,\n (snap) => {\n try {\n setData([snap.data()]);\n } catch (err) {\n showBoundary(err as Error);\n }\n },\n (error) => showBoundary(error),\n );\n return () => unsubscribe();\n },\n (data) => mutate(data, mutationConfig),\n );\n\n const setData = useCallback((newData: T) => setDocument<T>(ref, newData, mutate), [mutate, ref]);\n return [data![0], setData] as const;\n}\n\nasync function setDocument<T>(ref: DocumentReference<T>, newDoc: T, mutator: KeyedMutator<[T?]>) {\n await mutator(\n async () => {\n await setDoc(ref, newDoc);\n return [newDoc];\n },\n { ...mutationConfig, optimisticData: [newDoc] },\n );\n}\n\nasync function fetcher<T>(ref: DocumentReference<T>): Promise<[T?]> {\n const snapshot = await getDoc(ref);\n if (!snapshot.exists()) {\n return [undefined];\n }\n return [snapshot.data({ serverTimestamps: \"estimate\" })];\n}\n"],"names":["mutationConfig","useDocument","path","id","converter","data","setData","useDocumentOptional","db","useDb","showBoundary","useErrorBoundary","ref","doc","swrConfig","mutate","useSWR","fetcher","useSubscriptionListener","unsubscribe","onSnapshot","snap","err","error","useCallback","newData","setDocument","newDoc","mutator","setDoc","snapshot","getDoc"],"mappings":";;;;;;AAiBA,MAAMA,IAAiC;AAAA,EACrC,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,eAAe;AACjB;AAEO,SAASC,EAAeC,GAAcC,GAAYC,GAAsC;AAC7F,QAAM,CAACC,GAAMC,CAAO,IAAIC,EAAuBL,GAAMC,GAAIC,CAAS;AAClE,MAAI,CAACC,EAAM,OAAM,IAAI,MAAM,YAAYH,CAAI,IAAIC,CAAE,YAAY;AAC7D,SAAO,CAACE,GAAMC,CAAO;AACvB;AAEO,SAASC,EACdL,GACAC,GACAC,GACA;AACA,QAAMI,IAAKC,EAAA,GACL,EAAE,cAAAC,EAAA,IAAiBC,EAAA,GAEnBC,IAAMC,EAAIL,GAAIN,GAAMC,CAAE,EAAE,cAAcC,CAAS,GAE/CU,IAA8B;AAAA,IAClC,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,UAAU;AAAA,EAAA,GAGN,EAAE,MAAAT,GAAM,QAAAU,EAAA,IAAWC,EAAaJ,EAAI,MAAM,MAAMK,EAAQL,CAAG,GAAGE,CAAS;AAE7E,EAAAI;AAAA,IACEN,EAAI;AAAA,IACJ,CAACN,MAAY;AACX,YAAMa,IAAcC;AAAA,QAClBR;AAAA,QACA,CAACS,MAAS;AACR,cAAI;AACFf,YAAAA,EAAQ,CAACe,EAAK,KAAA,CAAM,CAAC;AAAA,UACvB,SAASC,GAAK;AACZ,YAAAZ,EAAaY,CAAY;AAAA,UAC3B;AAAA,QACF;AAAA,QACA,CAACC,MAAUb,EAAaa,CAAK;AAAA,MAAA;AAE/B,aAAO,MAAMJ,EAAA;AAAA,IACf;AAAA,IACA,CAACd,MAASU,EAAOV,GAAML,CAAc;AAAA,EAAA;AAGvC,QAAMM,IAAUkB,EAAY,CAACC,MAAeC,EAAed,GAAKa,GAASV,CAAM,GAAG,CAACA,GAAQH,CAAG,CAAC;AAC/F,SAAO,CAACP,EAAM,CAAC,GAAGC,CAAO;AAC3B;AAEA,eAAeoB,EAAed,GAA2Be,GAAWC,GAA6B;AAC/F,QAAMA;AAAA,IACJ,aACE,MAAMC,EAAOjB,GAAKe,CAAM,GACjB,CAACA,CAAM;AAAA,IAEhB,EAAE,GAAG3B,GAAgB,gBAAgB,CAAC2B,CAAM,EAAA;AAAA,EAAE;AAElD;AAEA,eAAeV,EAAWL,GAA0C;AAClE,QAAMkB,IAAW,MAAMC,EAAOnB,CAAG;AACjC,SAAKkB,EAAS,WAGP,CAACA,EAAS,KAAK,EAAE,kBAAkB,WAAA,CAAY,CAAC,IAF9C,CAAC,MAAS;AAGrB;"}
@@ -1,42 +1,46 @@
1
- import { useState as a, useEffect as l } from "react";
2
- const o = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map();
3
- function m(s, i) {
4
- const e = d(s, i);
5
- if (!e.data) throw e.promise;
6
- const [t, n] = a(e.data.value);
7
- return l(() => (e.listeners.add(n), () => void e.listeners.delete(n)), [e]), t;
1
+ import { use as f, useState as a, useEffect as l } from "react";
2
+ const u = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
3
+ function g(s, n) {
4
+ const e = b(s, n);
5
+ f(e.promise);
6
+ const [t, i] = a(e.data.value);
7
+ return l(() => (e.listeners.add(i), () => {
8
+ e.listeners.delete(i);
9
+ }), [e]), t;
8
10
  }
9
- function g(s, i, e) {
10
- const t = d(s, i);
11
- l(() => (t.listeners.add(e), () => void t.listeners.delete(e)), [t, e]);
11
+ function S(s, n, e) {
12
+ const t = b(s, n);
13
+ l(() => (t.listeners.add(e), () => {
14
+ t.listeners.delete(e);
15
+ }), [t, e]);
12
16
  }
13
- function d(s, i) {
14
- let e = o.get(s);
17
+ function b(s, n) {
18
+ let e = u.get(s);
15
19
  if (!e) {
16
20
  let t;
17
- const n = new Promise((r) => {
21
+ const i = new Promise((r) => {
18
22
  t = r;
19
- }), b = i((r) => {
23
+ }), d = n((r) => {
20
24
  t();
21
- const c = o.get(s);
25
+ const c = u.get(s);
22
26
  if (c) {
23
27
  c.data = { value: r };
24
28
  for (const p of c.listeners)
25
29
  p(r);
26
30
  }
27
31
  });
28
- e = { promise: n, unsubscribe: b, listeners: /* @__PURE__ */ new Set() }, o.set(s, e);
32
+ e = { promise: i, unsubscribe: d, listeners: /* @__PURE__ */ new Set() }, u.set(s, e);
29
33
  }
30
- return l(() => (clearTimeout(u.get(s)), () => {
31
- clearTimeout(u.get(s));
34
+ return l(() => (clearTimeout(o.get(s)), () => {
35
+ clearTimeout(o.get(s));
32
36
  const t = setTimeout(() => {
33
- e?.listeners.size || (e?.unsubscribe?.(), o.delete(s), u.delete(s));
37
+ e?.listeners.size || (e?.unsubscribe?.(), u.delete(s), o.delete(s));
34
38
  }, 1e3);
35
- u.set(s, t);
39
+ o.set(s, t);
36
40
  }), [s, e]), e;
37
41
  }
38
42
  export {
39
- m as useSubscription,
40
- g as useSubscriptionListener
43
+ g as useSubscription,
44
+ S as useSubscriptionListener
41
45
  };
42
46
  //# sourceMappingURL=subscription.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"subscription.js","sources":["../../../../src/web/hooks/subscription.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\ntype Subscription<T> = {\n promise: Promise<void>;\n unsubscribe?: () => void;\n listeners: Set<(data: T) => void>;\n data?: { value: T };\n};\n\nconst subscriptions = new Map<string, Subscription<any>>();\nconst pendingUnsubscribes = new Map<string, number>();\n\nexport function useSubscription<T>(\n key: string,\n subscribe: (set: (value: T) => void) => (() => void) | undefined,\n) {\n const subscription = useBaseSubscription(key, subscribe);\n if (!subscription.data) throw subscription.promise;\n\n const [value, setValue] = useState(subscription.data.value);\n useEffect(() => {\n subscription.listeners.add(setValue);\n return () => void subscription.listeners.delete(setValue);\n }, [subscription]);\n\n return value;\n}\n\nexport function useSubscriptionListener<T>(\n key: string,\n subscribe: (set: (value: T) => void) => (() => void) | undefined,\n onData: (value: T) => void,\n) {\n const subscription = useBaseSubscription(key, subscribe);\n\n useEffect(() => {\n subscription.listeners.add(onData);\n return () => void subscription.listeners.delete(onData);\n }, [subscription, onData]);\n}\n\nfunction useBaseSubscription<T>(\n key: string,\n subscribe: (set: (value: T) => void) => (() => void) | undefined,\n): Subscription<T> {\n let subscription = subscriptions.get(key) as Subscription<T>;\n if (!subscription) {\n let resolve!: () => void;\n const promise = new Promise<void>((r) => {\n resolve = r;\n });\n\n const unsubscribe = subscribe((value) => {\n resolve();\n const sub = subscriptions.get(key);\n if (sub) {\n sub.data = { value };\n for (const listener of sub.listeners) {\n listener(value);\n }\n }\n });\n subscription = { promise, unsubscribe, listeners: new Set() };\n subscriptions.set(key, subscription);\n }\n\n useEffect(() => {\n clearTimeout(pendingUnsubscribes.get(key));\n return () => {\n clearTimeout(pendingUnsubscribes.get(key));\n const id = setTimeout(() => {\n if (subscription?.listeners.size) return;\n subscription?.unsubscribe?.();\n subscriptions.delete(key);\n pendingUnsubscribes.delete(key);\n }, 1000);\n pendingUnsubscribes.set(key, id as any);\n };\n }, [key, subscription]);\n\n return subscription;\n}\n"],"names":["subscriptions","pendingUnsubscribes","useSubscription","key","subscribe","subscription","useBaseSubscription","value","setValue","useState","useEffect","useSubscriptionListener","onData","resolve","promise","unsubscribe","sub","listener","id"],"mappings":";AASA,MAAMA,wBAAoB,IAAA,GACpBC,wBAA0B,IAAA;AAEzB,SAASC,EACdC,GACAC,GACA;AACA,QAAMC,IAAeC,EAAoBH,GAAKC,CAAS;AACvD,MAAI,CAACC,EAAa,KAAM,OAAMA,EAAa;AAE3C,QAAM,CAACE,GAAOC,CAAQ,IAAIC,EAASJ,EAAa,KAAK,KAAK;AAC1D,SAAAK,EAAU,OACRL,EAAa,UAAU,IAAIG,CAAQ,GAC5B,MAAM,KAAKH,EAAa,UAAU,OAAOG,CAAQ,IACvD,CAACH,CAAY,CAAC,GAEVE;AACT;AAEO,SAASI,EACdR,GACAC,GACAQ,GACA;AACA,QAAMP,IAAeC,EAAoBH,GAAKC,CAAS;AAEvD,EAAAM,EAAU,OACRL,EAAa,UAAU,IAAIO,CAAM,GAC1B,MAAM,KAAKP,EAAa,UAAU,OAAOO,CAAM,IACrD,CAACP,GAAcO,CAAM,CAAC;AAC3B;AAEA,SAASN,EACPH,GACAC,GACiB;AACjB,MAAIC,IAAeL,EAAc,IAAIG,CAAG;AACxC,MAAI,CAACE,GAAc;AACjB,QAAIQ;AACJ,UAAMC,IAAU,IAAI,QAAc,CAAC,MAAM;AACvC,MAAAD,IAAU;AAAA,IACZ,CAAC,GAEKE,IAAcX,EAAU,CAACG,MAAU;AACvC,MAAAM,EAAA;AACA,YAAMG,IAAMhB,EAAc,IAAIG,CAAG;AACjC,UAAIa,GAAK;AACP,QAAAA,EAAI,OAAO,EAAE,OAAAT,EAAA;AACb,mBAAWU,KAAYD,EAAI;AACzB,UAAAC,EAASV,CAAK;AAAA,MAElB;AAAA,IACF,CAAC;AACD,IAAAF,IAAe,EAAE,SAAAS,GAAS,aAAAC,GAAa,WAAW,oBAAI,MAAI,GAC1Df,EAAc,IAAIG,GAAKE,CAAY;AAAA,EACrC;AAEA,SAAAK,EAAU,OACR,aAAaT,EAAoB,IAAIE,CAAG,CAAC,GAClC,MAAM;AACX,iBAAaF,EAAoB,IAAIE,CAAG,CAAC;AACzC,UAAMe,IAAK,WAAW,MAAM;AAC1B,MAAIb,GAAc,UAAU,SAC5BA,GAAc,cAAA,GACdL,EAAc,OAAOG,CAAG,GACxBF,EAAoB,OAAOE,CAAG;AAAA,IAChC,GAAG,GAAI;AACP,IAAAF,EAAoB,IAAIE,GAAKe,CAAS;AAAA,EACxC,IACC,CAACf,GAAKE,CAAY,CAAC,GAEfA;AACT;"}
1
+ {"version":3,"file":"subscription.js","sources":["../../../../src/web/hooks/subscription.ts"],"sourcesContent":["import { use, useEffect, useState } from \"react\";\n\ntype Subscription<T> = {\n promise: Promise<void>;\n unsubscribe?: () => void;\n listeners: Set<(data: T) => void>;\n data?: { value: T };\n};\n\nconst subscriptions = new Map<string, Subscription<any>>();\nconst pendingUnsubscribes = new Map<string, number>();\n\nexport function useSubscription<T>(\n key: string,\n subscribe: (set: (value: T) => void) => (() => void) | undefined,\n) {\n const subscription = useBaseSubscription(key, subscribe);\n use(subscription.promise);\n\n const [value, setValue] = useState(subscription.data!.value);\n useEffect(() => {\n subscription.listeners.add(setValue);\n return () => void subscription.listeners.delete(setValue);\n }, [subscription]);\n\n return value;\n}\n\nexport function useSubscriptionListener<T>(\n key: string,\n subscribe: (set: (value: T) => void) => (() => void) | undefined,\n onData: (value: T) => void,\n) {\n const subscription = useBaseSubscription(key, subscribe);\n\n useEffect(() => {\n subscription.listeners.add(onData);\n return () => void subscription.listeners.delete(onData);\n }, [subscription, onData]);\n}\n\nfunction useBaseSubscription<T>(\n key: string,\n subscribe: (set: (value: T) => void) => (() => void) | undefined,\n): Subscription<T> {\n let subscription = subscriptions.get(key) as Subscription<T>;\n if (!subscription) {\n let resolve!: () => void;\n const promise = new Promise<void>((r) => {\n resolve = r;\n });\n\n const unsubscribe = subscribe((value) => {\n resolve();\n const sub = subscriptions.get(key);\n if (sub) {\n sub.data = { value };\n for (const listener of sub.listeners) {\n listener(value);\n }\n }\n });\n subscription = { promise, unsubscribe, listeners: new Set() };\n subscriptions.set(key, subscription);\n }\n\n useEffect(() => {\n clearTimeout(pendingUnsubscribes.get(key));\n return () => {\n clearTimeout(pendingUnsubscribes.get(key));\n const id = setTimeout(() => {\n if (subscription?.listeners.size) return;\n subscription?.unsubscribe?.();\n subscriptions.delete(key);\n pendingUnsubscribes.delete(key);\n }, 1000);\n pendingUnsubscribes.set(key, id as any);\n };\n }, [key, subscription]);\n\n return subscription;\n}\n"],"names":["subscriptions","pendingUnsubscribes","useSubscription","key","subscribe","subscription","useBaseSubscription","use","value","setValue","useState","useEffect","useSubscriptionListener","onData","resolve","promise","unsubscribe","sub","listener","id"],"mappings":";AASA,MAAMA,wBAAoB,IAAA,GACpBC,wBAA0B,IAAA;AAEzB,SAASC,EACdC,GACAC,GACA;AACA,QAAMC,IAAeC,EAAoBH,GAAKC,CAAS;AACvD,EAAAG,EAAIF,EAAa,OAAO;AAExB,QAAM,CAACG,GAAOC,CAAQ,IAAIC,EAASL,EAAa,KAAM,KAAK;AAC3D,SAAAM,EAAU,OACRN,EAAa,UAAU,IAAII,CAAQ,GAC5B,MAAA;AAAM,IAAKJ,EAAa,UAAU,OAAOI,CAAQ;AAAA,MACvD,CAACJ,CAAY,CAAC,GAEVG;AACT;AAEO,SAASI,EACdT,GACAC,GACAS,GACA;AACA,QAAMR,IAAeC,EAAoBH,GAAKC,CAAS;AAEvD,EAAAO,EAAU,OACRN,EAAa,UAAU,IAAIQ,CAAM,GAC1B,MAAA;AAAM,IAAKR,EAAa,UAAU,OAAOQ,CAAM;AAAA,MACrD,CAACR,GAAcQ,CAAM,CAAC;AAC3B;AAEA,SAASP,EACPH,GACAC,GACiB;AACjB,MAAIC,IAAeL,EAAc,IAAIG,CAAG;AACxC,MAAI,CAACE,GAAc;AACjB,QAAIS;AACJ,UAAMC,IAAU,IAAI,QAAc,CAAC,MAAM;AACvC,MAAAD,IAAU;AAAA,IACZ,CAAC,GAEKE,IAAcZ,EAAU,CAACI,MAAU;AACvC,MAAAM,EAAA;AACA,YAAMG,IAAMjB,EAAc,IAAIG,CAAG;AACjC,UAAIc,GAAK;AACP,QAAAA,EAAI,OAAO,EAAE,OAAAT,EAAA;AACb,mBAAWU,KAAYD,EAAI;AACzB,UAAAC,EAASV,CAAK;AAAA,MAElB;AAAA,IACF,CAAC;AACD,IAAAH,IAAe,EAAE,SAAAU,GAAS,aAAAC,GAAa,WAAW,oBAAI,MAAI,GAC1DhB,EAAc,IAAIG,GAAKE,CAAY;AAAA,EACrC;AAEA,SAAAM,EAAU,OACR,aAAaV,EAAoB,IAAIE,CAAG,CAAC,GAClC,MAAM;AACX,iBAAaF,EAAoB,IAAIE,CAAG,CAAC;AACzC,UAAMgB,IAAK,WAAW,MAAM;AAC1B,MAAId,GAAc,UAAU,SAC5BA,GAAc,cAAA,GACdL,EAAc,OAAOG,CAAG,GACxBF,EAAoB,OAAOE,CAAG;AAAA,IAChC,GAAG,GAAI;AACP,IAAAF,EAAoB,IAAIE,GAAKgB,CAAS;AAAA,EACxC,IACC,CAAChB,GAAKE,CAAY,CAAC,GAEfA;AACT;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olinfo/quizms-firebase",
3
- "version": "4.0.1",
3
+ "version": "4.1.1",
4
4
  "type": "module",
5
5
  "author": "Alessandro Bortolin <bortolin.alessandro@outlook.it>",
6
6
  "license": "MIT",
@@ -26,40 +26,43 @@
26
26
  "dist"
27
27
  ],
28
28
  "dependencies": {
29
- "@inquirer/prompts": "^7.10.1",
30
- "@noble/hashes": "^1.8.0",
31
- "@olinfo/react-components": "^0.12.0",
29
+ "@inquirer/prompts": "^8.2.1",
30
+ "@olinfo/react-components": "^0.12.1",
31
+ "@trpc/client": "^11.10.0",
32
+ "@trpc/server": "^11.10.0",
32
33
  "@types/cli-progress": "^3.11.6",
34
+ "@types/express": "^5.0.6",
35
+ "@types/express-serve-static-core": "^5.1.1",
33
36
  "@types/lodash-es": "^4.17.12",
34
37
  "@types/picomatch": "^4.0.2",
35
- "ag-grid-community": "^33.3.2",
38
+ "ag-grid-community": "^35.1.0",
36
39
  "cli-progress": "^3.12.0",
37
40
  "clsx": "^2.1.1",
38
- "commander": "^14.0.2",
41
+ "commander": "^14.0.3",
39
42
  "date-fns": "^4.1.0",
40
- "fastify": "^5.6.2",
41
- "firebase": "^12.6.0",
42
- "firebase-admin": "^13.6.0",
43
- "firebase-functions": "^7.0.0",
44
- "lodash-es": "^4.17.21",
45
- "lucide-react": "^0.553.0",
46
- "picocolors": "^1.1.1",
43
+ "express": "^5.2.1",
44
+ "fastify": "^5.7.4",
45
+ "firebase": "^12.9.0",
46
+ "firebase-admin": "^13.6.1",
47
+ "firebase-functions": "^7.0.5",
48
+ "lodash-es": "^4.17.23",
49
+ "lucide-react": "^0.562.0",
47
50
  "picomatch": "^4.0.3",
48
- "react-error-boundary": "^5.0.0",
51
+ "react-error-boundary": "~6.0.3",
49
52
  "react-markdown": "^10.1.0",
50
53
  "rollup-plugin-node-externals": "^8.1.2",
51
54
  "rollup-preserve-directives": "^1.1.3",
52
- "swr": "^2.3.7",
55
+ "superjson": "^2.2.6",
56
+ "swr": "^2.4.0",
53
57
  "tinyglobby": "^0.2.15",
54
- "vite": "^7.2.6",
58
+ "vite": "^7.3.1",
55
59
  "vite-plugin-dts": "^4.5.4",
56
- "vite-tsconfig-paths": "^5.1.4",
57
- "wouter": "^3.8.1",
58
- "zod": "^3.25.76",
59
- "@olinfo/quizms": "^4.0.0"
60
+ "wouter": "^3.9.0",
61
+ "zod": "^4.3.6",
62
+ "@olinfo/quizms": "^4.1.1"
60
63
  },
61
64
  "peerDependencies": {
62
- "react": "~19.1"
65
+ "react": "~19.1.4"
63
66
  },
64
67
  "postcss": {
65
68
  "plugins": {
@@ -67,11 +70,12 @@
67
70
  }
68
71
  },
69
72
  "devDependencies": {
70
- "@biomejs/biome": "^2.3.8",
71
- "@google-cloud/storage": "^7.18.0",
72
- "@types/react": "^19.2.7",
73
+ "@biomejs/biome": "^2.4.2",
74
+ "@google-cloud/storage": "^7.19.0",
75
+ "@types/react": "^19.2.14",
73
76
  "@types/wicg-file-system-access": "^2023.10.7",
74
- "typescript": "5.8.2"
77
+ "typescript": "5.8.2",
78
+ "vite-tsconfig-paths": "^6.1.1"
75
79
  },
76
80
  "scripts": {
77
81
  "prebuild": "biome check && tsc --noEmit",
@@ -1,42 +0,0 @@
1
- import t from "zod";
2
- const i = t.object({
3
- action: t.literal("studentLogin"),
4
- contestId: t.string(),
5
- token: t.string(),
6
- userData: t.record(t.coerce.string()),
7
- extraData: t.record(t.any())
8
- }), a = t.object({
9
- action: t.literal("adminLogin"),
10
- username: t.string(),
11
- password: t.string()
12
- }), e = t.object({
13
- action: t.literal("teacherLogin"),
14
- username: t.string(),
15
- password: t.string()
16
- }), n = t.object({
17
- action: t.literal("teacherStartParticipation"),
18
- participationId: t.string()
19
- }), c = t.object({
20
- action: t.literal("teacherStopParticipation"),
21
- participationId: t.string()
22
- }), r = t.object({
23
- action: t.literal("teacherFinalizeParticipation"),
24
- participationId: t.string()
25
- }), s = t.discriminatedUnion("action", [
26
- a,
27
- i,
28
- e,
29
- n,
30
- c,
31
- r
32
- ]);
33
- export {
34
- a as adminLoginSchema,
35
- s as apiRequestSchema,
36
- i as studentLoginSchema,
37
- r as teacherFinalizeParticipationSchema,
38
- e as teacherLoginSchema,
39
- n as teacherStartParticipationSchema,
40
- c as teacherStopParticipationSchema
41
- };
42
- //# sourceMappingURL=schema.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema.js","sources":["../../../../src/functions/api/schema.ts"],"sourcesContent":["import z from \"zod\";\n\nexport const studentLoginSchema = z.object({\n action: z.literal(\"studentLogin\"),\n contestId: z.string(),\n token: z.string(),\n userData: z.record(z.coerce.string()),\n extraData: z.record(z.any()),\n});\nexport type StudentLogin = z.infer<typeof studentLoginSchema>;\n\nexport const adminLoginSchema = z.object({\n action: z.literal(\"adminLogin\"),\n username: z.string(),\n password: z.string(),\n});\nexport type AdminLogin = z.infer<typeof adminLoginSchema>;\n\nexport const teacherLoginSchema = z.object({\n action: z.literal(\"teacherLogin\"),\n username: z.string(),\n password: z.string(),\n});\nexport type TeacherLogin = z.infer<typeof teacherLoginSchema>;\n\nexport const teacherStartParticipationSchema = z.object({\n action: z.literal(\"teacherStartParticipation\"),\n participationId: z.string(),\n});\nexport type TeacherStartParticipation = z.infer<typeof teacherStartParticipationSchema>;\n\nexport const teacherStopParticipationSchema = z.object({\n action: z.literal(\"teacherStopParticipation\"),\n participationId: z.string(),\n});\nexport type TeacherStopParticipation = z.infer<typeof teacherStopParticipationSchema>;\n\nexport const teacherFinalizeParticipationSchema = z.object({\n action: z.literal(\"teacherFinalizeParticipation\"),\n participationId: z.string(),\n});\nexport type TeacherFinalizeParticipation = z.infer<typeof teacherFinalizeParticipationSchema>;\n\nexport const apiRequestSchema = z.discriminatedUnion(\"action\", [\n adminLoginSchema,\n studentLoginSchema,\n teacherLoginSchema,\n teacherStartParticipationSchema,\n teacherStopParticipationSchema,\n teacherFinalizeParticipationSchema,\n]);\n\nexport type ApiRequest = z.infer<typeof apiRequestSchema>;\n"],"names":["studentLoginSchema","z","adminLoginSchema","teacherLoginSchema","teacherStartParticipationSchema","teacherStopParticipationSchema","teacherFinalizeParticipationSchema","apiRequestSchema"],"mappings":";AAEO,MAAMA,IAAqBC,EAAE,OAAO;AAAA,EACzC,QAAQA,EAAE,QAAQ,cAAc;AAAA,EAChC,WAAWA,EAAE,OAAA;AAAA,EACb,OAAOA,EAAE,OAAA;AAAA,EACT,UAAUA,EAAE,OAAOA,EAAE,OAAO,QAAQ;AAAA,EACpC,WAAWA,EAAE,OAAOA,EAAE,KAAK;AAC7B,CAAC,GAGYC,IAAmBD,EAAE,OAAO;AAAA,EACvC,QAAQA,EAAE,QAAQ,YAAY;AAAA,EAC9B,UAAUA,EAAE,OAAA;AAAA,EACZ,UAAUA,EAAE,OAAA;AACd,CAAC,GAGYE,IAAqBF,EAAE,OAAO;AAAA,EACzC,QAAQA,EAAE,QAAQ,cAAc;AAAA,EAChC,UAAUA,EAAE,OAAA;AAAA,EACZ,UAAUA,EAAE,OAAA;AACd,CAAC,GAGYG,IAAkCH,EAAE,OAAO;AAAA,EACtD,QAAQA,EAAE,QAAQ,2BAA2B;AAAA,EAC7C,iBAAiBA,EAAE,OAAA;AACrB,CAAC,GAGYI,IAAiCJ,EAAE,OAAO;AAAA,EACrD,QAAQA,EAAE,QAAQ,0BAA0B;AAAA,EAC5C,iBAAiBA,EAAE,OAAA;AACrB,CAAC,GAGYK,IAAqCL,EAAE,OAAO;AAAA,EACzD,QAAQA,EAAE,QAAQ,8BAA8B;AAAA,EAChD,iBAAiBA,EAAE,OAAA;AACrB,CAAC,GAGYM,IAAmBN,EAAE,mBAAmB,UAAU;AAAA,EAC7DC;AAAA,EACAF;AAAA,EACAG;AAAA,EACAC;AAAA,EACAC;AAAA,EACAC;AACF,CAAC;"}