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

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.
@@ -1,12 +1,18 @@
1
- import { HttpsFunction } from 'firebase-functions/v2/https';
1
+ import { HttpsFunction, Request } from 'firebase-functions/v2/https';
2
2
  export interface OGData {
3
3
  title: string;
4
4
  description: string;
5
5
  image: string;
6
6
  }
7
+ export interface SSRResolveContext {
8
+ req: Request;
9
+ pathname: string;
10
+ searchParams: URLSearchParams;
11
+ match: RegExpMatchArray;
12
+ }
7
13
  export interface SSRResolver {
8
14
  pattern: RegExp;
9
- resolve: (id: string) => Promise<OGData | null>;
15
+ resolve: (id: string, context: SSRResolveContext) => Promise<OGData | null>;
10
16
  }
11
17
  export interface SSRDynamicOGConfig {
12
18
  spaUrl: string;
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.replace(/(<title>)[^<]*(<\/title>)/i,`$1${i}$2`);return 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,`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;try{let e=r;for(let t of i){let n=o.match(t.pattern);if(n){let r=n[1]??n[0];try{let n=await t.resolve(r);if(n){e=n;break}}catch(e){console.error(`[SSRDynamicOG] Failed to resolve ID "${r}" for pattern ${t.pattern}:`,e)}}}let n=d(await c(),e.title,e.description,e.image);console.log(`[SSRDynamicOG] ${o} → ${e.title} (${Date.now()-a}ms)`),t.setHeader(`Content-Type`,`text/html; charset=utf-8`),t.status(200).send(n)}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");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;
package/dist/index.mjs CHANGED
@@ -47,30 +47,34 @@ function o(e) {
47
47
  return s;
48
48
  }
49
49
  function d(e, t, n, r) {
50
- let i = l(t), a = e.replace(/(<title>)[^<]*(<\/title>)/i, `$1${i}$2`);
51
- return 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, "name", "twitter:title", t), a = u(a, "name", "twitter:description", n), a = u(a, "name", "twitter:image", r), a;
50
+ let i = l(t), a = e;
51
+ 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;
52
52
  }
53
53
  return t({ region: a }, async (e, t) => {
54
- let a = Date.now(), o = e.path;
54
+ let a = Date.now(), o = e.path, s = new URL(e.url, n), l = s.searchParams;
55
55
  try {
56
- let e = r;
56
+ let n = r;
57
57
  for (let t of i) {
58
- let n = o.match(t.pattern);
59
- if (n) {
60
- let r = n[1] ?? n[0];
61
- try {
62
- let n = await t.resolve(r);
63
- if (n) {
64
- e = n;
65
- break;
66
- }
67
- } catch (e) {
68
- console.error(`[SSRDynamicOG] Failed to resolve ID "${r}" for pattern ${t.pattern}:`, e);
58
+ let r = o.match(t.pattern);
59
+ if (!r) continue;
60
+ let i = r[1] ?? r[0];
61
+ try {
62
+ let a = await t.resolve(i, {
63
+ req: e,
64
+ pathname: o,
65
+ searchParams: l,
66
+ match: r
67
+ });
68
+ if (a) {
69
+ n = a;
70
+ break;
69
71
  }
72
+ } catch (e) {
73
+ console.error(`[SSRDynamicOG] Failed to resolve "${o}${s.search}" with pattern ${t.pattern}:`, e);
70
74
  }
71
75
  }
72
- let n = d(await c(), e.title, e.description, e.image);
73
- console.log(`[SSRDynamicOG] ${o} → ${e.title} (${Date.now() - a}ms)`), t.setHeader("Content-Type", "text/html; charset=utf-8"), t.status(200).send(n);
76
+ let u = d(await c(), n.title, n.description, n.image);
77
+ 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);
74
78
  } catch (e) {
75
79
  console.error("[SSRDynamicOG] error:", e), t.redirect(302, n);
76
80
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ienlab/cloud-functions-library",
3
- "version": "1.0.0-dev.11",
3
+ "version": "1.0.0-dev.12",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",