@ienlab/cloud-functions-library 1.0.0-dev.12 → 1.0.0-dev.14

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/dist/index.js CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("firebase-admin/firestore"),t=require("firebase-functions/v2/https");function n(e){return{...e.data(),id:e.id}}function r(e,t,n){let r=e.headers.origin;return r&&n.includes(r)&&(t.set(`Access-Control-Allow-Origin`,r),t.set(`Vary`,`Origin`)),t.set(`Access-Control-Allow-Methods`,`POST, OPTIONS`),t.set(`Access-Control-Allow-Headers`,`Content-Type, Authorization`),e.method===`OPTIONS`?(t.status(204).send(),!1):e.method===`POST`?!0:(t.status(405).send({error:`Method Not Allowed`}),!1)}var i=()=>({updateAt:e.FieldValue.serverTimestamp(),deletedAt:e.FieldValue.serverTimestamp()}),a=()=>({updateAt:e.FieldValue.serverTimestamp(),deletedAt:null});function o(e){let{spaUrl:n,defaultOG:r,resolvers:i,region:a=`asia-northeast3`}=e,o=null,s=0;function c(){let e=Date.now();return(!o||e-s>18e5)&&(s=e,o=fetch(n,{signal:AbortSignal.timeout(5e3)}).then(async e=>{if(!e.ok)throw o=null,s=0,Error(`Failed to fetch template: ${e.status}`);return e.text()}).catch(e=>{throw o=null,s=0,e})),o}function l(e){return e?String(e).replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#039;`):``}function u(e,t,n,r){let i=l(r),a=RegExp(`(<meta\\s+[^>]*${t}=["']${n}["'][^>]*>)`,`gi`),o=!1,s=e.replace(a,e=>(o=!0,/\bcontent=/i.test(e)?e.replace(/\bcontent=(["'])(.*?)\1/i,`content=$1${i}$1`):e.replace(/(\/?>)$/,` content="${i}"$1`)));if(!o){let e=`<meta ${t}="${n}" content="${i}">`;return s.replace(/(<\/head>)/i,`${e}\n$1`)}return s}function d(e,t,n,r){let i=l(t),a=e;return a=/<title>.*<\/title>/i.test(a)?a.replace(/(<title>)[^<]*(<\/title>)/i,`$1${i}$2`):a.replace(/(<\/head>)/i,`<title>${i}</title>\n$1`),a=u(a,`name`,`description`,n),a=u(a,`property`,`og:title`,t),a=u(a,`property`,`og:description`,n),a=u(a,`property`,`og:image`,r),a=u(a,`property`,`og:type`,`website`),a=u(a,`name`,`twitter:card`,`summary_large_image`),a=u(a,`name`,`twitter:title`,t),a=u(a,`name`,`twitter:description`,n),a=u(a,`name`,`twitter:image`,r),a}return(0,t.onRequest)({region:a},async(e,t)=>{let a=Date.now(),o=e.path,s=new URL(e.url,n),l=s.searchParams;try{let n=r;for(let t of i){let r=o.match(t.pattern);if(!r)continue;let i=r[1]??r[0];try{let a=await t.resolve(i,{req:e,pathname:o,searchParams:l,match:r});if(a){n=a;break}}catch(e){console.error(`[SSRDynamicOG] Failed to resolve "${o}${s.search}" with pattern ${t.pattern}:`,e)}}let u=d(await c(),n.title,n.description,n.image);console.log(`[SSRDynamicOG] ${o}${s.search} → ${n.title} (${Date.now()-a}ms)`),t.setHeader(`Content-Type`,`text/html; charset=utf-8`),t.status(200).send(u)}catch(e){console.error(`[SSRDynamicOG] error:`,e),t.redirect(302,n)}})}exports.applyCors=r,exports.createSSRDynamicOG=o,exports.del=i,exports.snapshotToData=n,exports.undel=a;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("firebase-admin/firestore"),t=require("firebase-functions/v2/https");var n=[`ko`,`en`],r=null;function i(e){r=e}var a={get(e,t=`ko`){let i=r?.();return e[n.includes(i)?i:t]??e[t]},ko(e){return e.ko}};function o(e){return{...e.data(),id:e.id}}function s(e,t,n){let r=e.headers.origin;return r&&n.includes(r)&&(t.set(`Access-Control-Allow-Origin`,r),t.set(`Vary`,`Origin`)),t.set(`Access-Control-Allow-Methods`,`POST, OPTIONS`),t.set(`Access-Control-Allow-Headers`,`Content-Type, Authorization`),e.method===`OPTIONS`?(t.status(204).send(),!1):e.method===`POST`?!0:(t.status(405).send({error:`Method Not Allowed`}),!1)}var c=()=>({updateAt:e.FieldValue.serverTimestamp(),deletedAt:e.FieldValue.serverTimestamp()}),l=()=>({updateAt:e.FieldValue.serverTimestamp(),deletedAt:null});function u(e){let{spaUrl:n,defaultOG:r,resolvers:i,region:a=`asia-northeast3`}=e,o=null,s=0;function c(){let e=Date.now();return(!o||e-s>18e5)&&(s=e,o=fetch(n,{signal:AbortSignal.timeout(5e3)}).then(async e=>{if(!e.ok)throw o=null,s=0,Error(`Failed to fetch template: ${e.status}`);return e.text()}).catch(e=>{throw o=null,s=0,e})),o}function l(e){return e?String(e).replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#039;`):``}function u(e,t,n,r){let i=l(r),a=RegExp(`(<meta\\s+[^>]*${t}=["']${n}["'][^>]*>)`,`gi`),o=!1,s=e.replace(a,e=>(o=!0,/\bcontent=/i.test(e)?e.replace(/\bcontent=(["'])(.*?)\1/i,`content=$1${i}$1`):e.replace(/(\/?>)$/,` content="${i}"$1`)));if(!o){let e=`<meta ${t}="${n}" content="${i}">`;return s.replace(/(<\/head>)/i,`${e}\n$1`)}return s}function d(e,t,n,r){let i=l(t),a=e;return a=/<title>.*<\/title>/i.test(a)?a.replace(/(<title>)[^<]*(<\/title>)/i,`$1${i}$2`):a.replace(/(<\/head>)/i,`<title>${i}</title>\n$1`),a=u(a,`name`,`description`,n),a=u(a,`property`,`og:title`,t),a=u(a,`property`,`og:description`,n),a=u(a,`property`,`og:image`,r),a=u(a,`property`,`og:type`,`website`),a=u(a,`name`,`twitter:card`,`summary_large_image`),a=u(a,`name`,`twitter:title`,t),a=u(a,`name`,`twitter:description`,n),a=u(a,`name`,`twitter:image`,r),a}return(0,t.onRequest)({region:a},async(e,t)=>{let a=Date.now(),o=e.path,s=new URL(e.url,n),l=s.searchParams;try{let n=r;for(let t of i){let r=o.match(t.pattern);if(!r)continue;let i=r[1]??r[0];try{let a=await t.resolve(i,{req:e,pathname:o,searchParams:l,match:r});if(a){n=a;break}}catch(e){console.error(`[SSRDynamicOG] Failed to resolve "${o}${s.search}" with pattern ${t.pattern}:`,e)}}let u=d(await c(),n.title,n.description,n.image);console.log(`[SSRDynamicOG] ${o}${s.search} → ${n.title} (${Date.now()-a}ms)`),t.setHeader(`Content-Type`,`text/html; charset=utf-8`),t.status(200).send(u)}catch(e){console.error(`[SSRDynamicOG] error:`,e),t.redirect(302,n)}})}exports.Localized=a,exports.SUPPORTED_LOCALES=n,exports.applyCors=s,exports.createSSRDynamicOG=u,exports.del=c,exports.setLocalizedLocaleResolver=i,exports.snapshotToData=o,exports.undel=l;
package/dist/index.mjs CHANGED
@@ -1,7 +1,22 @@
1
1
  import { FieldValue as e } from "firebase-admin/firestore";
2
2
  import { onRequest as t } from "firebase-functions/v2/https";
3
+ //#region src/types/localized.ts
4
+ var n = ["ko", "en"], r = null;
5
+ function i(e) {
6
+ r = e;
7
+ }
8
+ var a = {
9
+ get(e, t = "ko") {
10
+ let i = r?.();
11
+ return e[n.includes(i) ? i : t] ?? e[t];
12
+ },
13
+ ko(e) {
14
+ return e.ko;
15
+ }
16
+ };
17
+ //#endregion
3
18
  //#region src/utils/firestore.ts
4
- function n(e) {
19
+ function o(e) {
5
20
  return {
6
21
  ...e.data(),
7
22
  id: e.id
@@ -9,22 +24,22 @@ function n(e) {
9
24
  }
10
25
  //#endregion
11
26
  //#region src/utils/cors.ts
12
- function r(e, t, n) {
27
+ function s(e, t, n) {
13
28
  let r = e.headers.origin;
14
29
  return r && n.includes(r) && (t.set("Access-Control-Allow-Origin", r), t.set("Vary", "Origin")), t.set("Access-Control-Allow-Methods", "POST, OPTIONS"), t.set("Access-Control-Allow-Headers", "Content-Type, Authorization"), e.method === "OPTIONS" ? (t.status(204).send(), !1) : e.method === "POST" ? !0 : (t.status(405).send({ error: "Method Not Allowed" }), !1);
15
30
  }
16
31
  //#endregion
17
32
  //#region src/constant/firestore.ts
18
- var i = () => ({
33
+ var c = () => ({
19
34
  updateAt: e.serverTimestamp(),
20
35
  deletedAt: e.serverTimestamp()
21
- }), a = () => ({
36
+ }), l = () => ({
22
37
  updateAt: e.serverTimestamp(),
23
38
  deletedAt: null
24
39
  });
25
40
  //#endregion
26
41
  //#region src/handlers/ssr-dynamic-og.ts
27
- function o(e) {
42
+ function u(e) {
28
43
  let { spaUrl: n, defaultOG: r, resolvers: i, region: a = "asia-northeast3" } = e, o = null, s = 0;
29
44
  function c() {
30
45
  let e = Date.now();
@@ -81,4 +96,4 @@ function o(e) {
81
96
  });
82
97
  }
83
98
  //#endregion
84
- export { r as applyCors, o as createSSRDynamicOG, i as del, n as snapshotToData, a as undel };
99
+ export { a as Localized, n as SUPPORTED_LOCALES, s as applyCors, u as createSSRDynamicOG, c as del, i as setLocalizedLocaleResolver, o as snapshotToData, l as undel };
@@ -1 +1,2 @@
1
1
  export * from './firestore';
2
+ export * from './localized';
@@ -0,0 +1,8 @@
1
+ export declare const SUPPORTED_LOCALES: readonly ["ko", "en"];
2
+ export type Locale = (typeof SUPPORTED_LOCALES)[number];
3
+ export type Localized<T, TLocale extends string = Locale> = Record<TLocale, T>;
4
+ export declare function setLocalizedLocaleResolver(resolver: () => string | undefined): void;
5
+ export declare const Localized: {
6
+ get<T>(value: Localized<T>, fallback?: Locale): T;
7
+ ko<T>(value: Localized<T>): T;
8
+ };
@@ -0,0 +1,7 @@
1
+ import { Dayjs } from 'dayjs';
2
+ export declare function createDateFormatters(locale?: string): {
3
+ dateFormat: (date: Date | Dayjs) => string;
4
+ dateFormatNoYear: (date: Date | Dayjs) => string;
5
+ dateFormatShort: (date: Date | Dayjs) => string;
6
+ dateFormatNoYearShort: (date: Date | Dayjs) => string;
7
+ };
@@ -0,0 +1,7 @@
1
+ import { Dayjs } from 'dayjs';
2
+ export declare function createDateTimeFormatters(locale?: string): {
3
+ dateTimeFormat: (date: Date | Dayjs, showSec?: boolean) => string;
4
+ dateTimeFormatShort: (date: Date | Dayjs, showSec?: boolean) => string;
5
+ dateTimeFormatNoYear: (date: Date | Dayjs, showSec?: boolean) => string;
6
+ dateTimeFormatNoYearShort: (date: Date | Dayjs, showSec?: boolean) => string;
7
+ };
@@ -0,0 +1,6 @@
1
+ import { default as dayjs } from 'dayjs';
2
+ export * from './date';
3
+ export * from './datetime';
4
+ export * from './time';
5
+ export * from './utils';
6
+ export default dayjs;
@@ -0,0 +1,12 @@
1
+ import { Dayjs } from 'dayjs';
2
+ export declare function createTimeFormatters(locale?: string): {
3
+ timeFormat24: (date: Date | Dayjs, showSec?: boolean) => string;
4
+ timeFormat24Short: (date: Date | Dayjs, showSec?: boolean) => string;
5
+ timeFormat12: (date: Date | Dayjs, showSec?: boolean) => string;
6
+ timeFormat12NoApm: (date: Date | Dayjs, showSec?: boolean) => string;
7
+ apmFormat: (date: Date | Dayjs) => string;
8
+ };
9
+ export declare function createDurationFormatter(locale?: string): {
10
+ minFormat: (minutes: number) => string;
11
+ minFormatShort: (minutes: number) => string;
12
+ };
@@ -0,0 +1,94 @@
1
+ import { Dayjs } from 'dayjs';
2
+ export declare const DATE_TIME_FORMATS: {
3
+ ko: {
4
+ date_format: {
5
+ default: string;
6
+ no_year: string;
7
+ no_year_short: string;
8
+ short: string;
9
+ };
10
+ date_time_format: {
11
+ default: {
12
+ no_sec: string;
13
+ sec: string;
14
+ };
15
+ no_year: {
16
+ no_sec: string;
17
+ sec: string;
18
+ short: {
19
+ no_sec: string;
20
+ sec: string;
21
+ };
22
+ };
23
+ short: {
24
+ no_sec: string;
25
+ sec: string;
26
+ };
27
+ };
28
+ time_format: {
29
+ apm: string;
30
+ f12: {
31
+ no_sec: string;
32
+ sec: string;
33
+ };
34
+ f12_no_apm: {
35
+ no_sec: string;
36
+ sec: string;
37
+ };
38
+ f24: {
39
+ no_sec: string;
40
+ sec: string;
41
+ };
42
+ f24_short: {
43
+ no_sec: string;
44
+ sec: string;
45
+ };
46
+ };
47
+ };
48
+ en: {
49
+ date_format: {
50
+ default: string;
51
+ no_year: string;
52
+ no_year_short: string;
53
+ short: string;
54
+ };
55
+ date_time_format: {
56
+ default: {
57
+ no_sec: string;
58
+ sec: string;
59
+ };
60
+ no_year: {
61
+ no_sec: string;
62
+ sec: string;
63
+ short: {
64
+ no_sec: string;
65
+ sec: string;
66
+ };
67
+ };
68
+ short: {
69
+ no_sec: string;
70
+ sec: string;
71
+ };
72
+ };
73
+ time_format: {
74
+ apm: string;
75
+ f12: {
76
+ no_sec: string;
77
+ sec: string;
78
+ };
79
+ f12_no_apm: {
80
+ no_sec: string;
81
+ sec: string;
82
+ };
83
+ f24: {
84
+ no_sec: string;
85
+ sec: string;
86
+ };
87
+ f24_short: {
88
+ no_sec: string;
89
+ sec: string;
90
+ };
91
+ };
92
+ };
93
+ };
94
+ export declare function formatBaseDateTime(date: Date | Dayjs, formatStr: string, locale?: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ienlab/cloud-functions-library",
3
- "version": "1.0.0-dev.12",
3
+ "version": "1.0.0-dev.14",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -11,27 +11,33 @@
11
11
  "types": "./dist/index.d.ts"
12
12
  }
13
13
  },
14
- "files": ["dist"],
14
+ "files": [
15
+ "dist"
16
+ ],
15
17
  "scripts": {
16
- "build": "vite build"
18
+ "build": "vite build",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest"
17
21
  },
18
- "dependencies": {},
19
22
  "peerDependencies": {
23
+ "dayjs": ">=1.11.0",
20
24
  "express": ">=4.0.0",
21
25
  "firebase-admin": ">=12.0.0",
22
26
  "firebase-functions": ">=6.0.0"
23
27
  },
24
28
  "devDependencies": {
29
+ "@eslint/js": "^10.0.1",
30
+ "@types/node": "^26.0.0",
31
+ "dayjs": "^1.11.21",
32
+ "eslint": "^10.5.0",
25
33
  "firebase-admin": "^13.10.0",
26
34
  "firebase-functions": "^7.2.5",
27
35
  "firebase-functions-test": "^3.5.0",
28
- "@eslint/js": "^10.0.1",
29
- "@types/node": "^25.9.1",
30
- "eslint": "^10.4.1",
31
36
  "globals": "^17.6.0",
32
37
  "typescript": "~6.0.3",
33
- "typescript-eslint": "^8.60.1",
38
+ "typescript-eslint": "^8.61.1",
34
39
  "vite": "^8.0.16",
35
- "vite-plugin-dts": "^5.0.2"
40
+ "vite-plugin-dts": "^5.0.2",
41
+ "vitest": "^4.1.9"
36
42
  }
37
43
  }