ts-glitter 20.4.2 → 20.4.3

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/src/index.ts CHANGED
@@ -152,402 +152,8 @@ export async function createAPP(dd: any) {
152
152
  path: file_path,
153
153
  app_name: dd.appName,
154
154
  root_path: '/' + encodeURI(dd.appName) + '/',
155
- seoManager: async req => {
156
- const og_url = req.headers['x-original-url'];
157
-
158
- try {
159
- if (req.query.state === 'google_login') {
160
- req.query.page = 'login';
161
- }
162
- let appName = dd.appName;
163
- if (req.query.appName) {
164
- appName = req.query.appName;
165
- } else if (og_url) {
166
- const new_app = (
167
- await db.query(
168
- `SELECT *
169
- FROM \`${saasConfig.SAAS_NAME}\`.app_config
170
- where LOWER(domain) = ?`,
171
- [og_url]
172
- )
173
- )[0];
174
- if (new_app && new_app.appName) {
175
- appName = new_app && new_app.appName;
176
- } else {
177
- return {
178
- head: '',
179
- body: `<script>window.location.href='https://shopnex.tw'</script>`,
180
- };
181
- }
182
- }
183
- req.headers['g-app'] = appName;
184
- const start = new Date().getTime();
185
- console.log(`getPageInfo==>`, (new Date().getTime() - start) / 1000);
186
- //要進行initial避免找不到DB
187
- await ApiPublic.createScheme(appName);
188
- const find_app = ApiPublic.app301.find(dd => {
189
- return dd.app_name === appName;
190
- });
191
- if (find_app) {
192
- const router = find_app.router.find(dd => {
193
- if (dd.legacy_url.startsWith('/')) {
194
- dd.legacy_url = dd.legacy_url.substring(1);
195
- }
196
- if (dd.new_url.startsWith('/')) {
197
- dd.new_url = dd.new_url.substring(1);
198
- }
199
- return dd.legacy_url === req.query.page;
200
- });
201
- if (router) {
202
- return {
203
- redirect: `https://${(await App.checkBrandAndMemberType(appName)).domain}/${router.new_url}`,
204
- };
205
- }
206
- }
207
- //SEO內容
208
- let seo_content: string[] = [];
209
- let [
210
- customCode,
211
- FBCode,
212
- store_info,
213
- language_label,
214
- check_schema,
215
- brandAndMemberType,
216
- login_config,
217
- ip_country,
218
- ] = await Promise.all([
219
- new User(appName).getConfigV2({
220
- key: 'ga4_config',
221
- user_id: 'manager',
222
- }),
223
- new User(appName).getConfigV2({
224
- key: 'login_fb_setting',
225
- user_id: 'manager',
226
- }),
227
- new User(appName).getConfigV2({
228
- key: 'store-information',
229
- user_id: 'manager',
230
- }),
231
- new User(appName).getConfigV2({
232
- key: 'language-label',
233
- user_id: 'manager',
234
- }),
235
- ApiPublic.createScheme(appName),
236
- App.checkBrandAndMemberType(appName),
237
- new User(req.get('g-app') as string, req.body.token).getConfigV2({
238
- key: 'login_config',
239
- user_id: 'manager',
240
- }),
241
- User.ipInfo((req.query.ip || req.headers['x-real-ip'] || req.ip) as string),
242
- ]);
243
- //取得多國語言
244
- const language: any = await SeoConfig.language(store_info, req);
245
- //插入瀏覽紀錄
246
- Monitor.insertHistory({
247
- req_type: 'file',
248
- req: req,
249
- });
250
- //取得SEO頁面資訊
251
- let data = await Seo.getPageInfo(appName, req.query.page as string, language);
252
- //首頁SEO
253
- let home_page_data = await (async () => {
254
- return await Seo.getPageInfo(appName, 'index', language);
255
- })();
256
- if(`${req.query.page}`.startsWith('products/') && !data){
257
- data=home_page_data
258
- }
259
- if (data && data.page_config) {
260
- data.page_config = data.page_config ?? {};
261
- const d = data.page_config.seo ?? {};
262
- //商品搜索
263
- if (`${req.query.page}`.startsWith('products/')) {
264
- await SeoConfig.productSEO({
265
- data,
266
- language,
267
- appName,
268
- product_id: req.query.product_id as any,
269
- page: req.query.page as any,
270
- });
271
- } else if (`${req.query.page}` === 'blogs') {
272
- //網誌目錄
273
- const seo = await new User(req.get('g-app') as string, req.body.token).getConfigV2({
274
- key: 'article_seo_data_' + language,
275
- user_id: 'manager',
276
- });
277
- data.page_config.seo.title = seo.title || data.page_config.seo.title;
278
- data.page_config.seo.content = seo.content || data.page_config.seo.content;
279
- data.page_config.seo.keywords = seo.keywords || data.page_config.seo.keywords;
280
- data.page_config.seo.image = seo.image || data.page_config.seo.image;
281
- data.page_config.seo.logo = seo.logo || data.page_config.seo.logo;
282
- } else if (`${req.query.page}`.startsWith('blogs/')) {
283
- //網誌搜索
284
- data.page_config.seo = await SeoConfig.articleSeo({
285
- article: req.query.article as any,
286
- page: req.query.page as any,
287
- language,
288
- appName,
289
- data,
290
- });
291
- } else if (`${req.query.page}`.startsWith('pages/')) {
292
- //頁面搜索
293
- await SeoConfig.articleSeo({
294
- article: req.query.article as any,
295
- page: req.query.page as any,
296
- language,
297
- appName,
298
- data,
299
- });
300
- } else if (['privacy', 'term', 'refund', 'delivery'].includes(`${req.query.page}`)) {
301
- data.page_config.seo = {
302
- title: Language.text(`${req.query.page}`, language),
303
- content: Language.text(`${req.query.page}`, language),
304
- };
305
- } else if (d.type !== 'custom') {
306
- data = home_page_data;
307
- }
308
- const preload =
309
- req.query.isIframe === 'true'
310
- ? {}
311
- : await App.preloadPageData(appName, req.query.page as any, language);
312
- data.page_config = data.page_config ?? {};
313
- data.page_config.seo = data.page_config.seo ?? {};
314
- const seo_detail = await getSeoDetail(appName, req);
315
- if (seo_detail) {
316
- Object.keys(seo_detail).map(dd => {
317
- data.page_config.seo[dd] = seo_detail[dd];
318
- });
319
- }
320
- let link_prefix = req.originalUrl.split('/')[1];
321
- if (link_prefix.includes('?')) {
322
- link_prefix = link_prefix.substring(0, link_prefix.indexOf('?'));
323
- }
324
- if (ConfigSetting.is_local) {
325
- if (link_prefix !== 'shopnex' && link_prefix !== 'codenex_v2') {
326
- link_prefix = '';
327
- }
328
- } else {
329
- link_prefix = '';
330
- }
331
- let distribution_code = '';
332
- req.query.page = req.query.page || 'index';
333
- if ((req.query.page as string).split('/')[0] === 'order_detail' && req.query.EndCheckout === '1') {
334
- distribution_code = `
335
- localStorage.setItem('distributionCode','');
336
- `;
337
- }
338
- console.log(`req.query.page`,req.query.page)
339
- //分銷連結頁面SEO
340
- if (
341
- (req.query.page as string).split('/')[0] === 'distribution' &&
342
- (req.query.page as string).split('/')[1]
343
- ) {
344
- distribution_code = await SeoConfig.distributionSEO({
345
- appName: appName,
346
- url: req.url,
347
- page: req.query.page as string,
348
- link_prefix: link_prefix,
349
- data,
350
- language,
351
- });
352
- }
353
- //分類頁面SEO
354
- if (
355
- (req.query.page as string).split('/')[0] === 'collections' &&
356
- (req.query.page as string).split('/')[1]
357
- ) {
358
- await SeoConfig.collectionSeo({ appName, language, data, page: req.query.page as string });
359
- }
360
- //FB像素
361
- if (FBCode) {
362
- //IOS系統必須同意後才可追蹤
363
- if(!((req.headers['user-agent'] as string).includes('iosGlitter') && !((req.headers['user-agent'] as string).includes('allow_track')))){
364
- seo_content.push(SeoConfig.fbCode(FBCode));
365
- }
366
- }
367
-
368
- const home_seo = home_page_data.page_config.seo || {};
369
- const head = [
370
- (() => {
371
- const d = data.page_config.seo;
372
- return html`
373
- ${(() => {
374
- if (req.query.type === 'editor') {
375
- return SeoConfig.editorSeo;
376
- } else {
377
- return html`<title>
378
- ${[home_seo.title_prefix || '', d.title || '', home_seo.title_suffix || ''].join('') ||
379
- '尚未設定標題'}
380
- </title>
381
- <link
382
- rel="canonical"
383
- href="${(() => {
384
- if (data.tag === 'index') {
385
- return `https://${brandAndMemberType.domain}`;
386
- } else if (req.query.page === 'blogs') {
387
- return `https://${brandAndMemberType.domain}/blogs`;
388
- } {
389
- return `https://${brandAndMemberType.domain}/${data.tag}`;
390
- }
391
- })()}"
392
- />
393
- ${((data.tag !== req.query.page || req.query.page === 'index-mobile') && req.query.page !== 'blogs')
394
- ? `<meta name="robots" content="noindex">`
395
- : `<meta name="robots" content="index, follow"/>`}
396
- <meta name="keywords" content="${(d.keywords || '尚未設定關鍵字').replace(/"/g, '&quot;')}" />
397
- <link
398
- id="appImage"
399
- rel="shortcut icon"
400
- href="${d.logo || home_seo.logo || ''}"
401
- type="image/x-icon"
402
- />
403
- <link rel="icon" href="${d.logo || home_seo.logo || ''}" type="image/png" sizes="128x128" />
404
- <meta property="og:image" content="${d.image || home_seo.image || ''}" />
405
- <meta
406
- property="og:title"
407
- content="${(d.title ?? '').replace(/\n/g, '').replace(/"/g, '&quot;')}"
408
- />
409
- <meta
410
- name="description"
411
- content="${(d.content ?? '').replace(/\n/g, '').replace(/"/g, '&quot;')}"
412
- />
413
- <meta
414
- name="og:description"
415
- content="${(d.content ?? '').replace(/\n/g, '').replace(/"/g, '&quot;')}"
416
- />
417
-
418
- ${[{ src: 'css/front-end.css', type: 'text/css' }]
419
- .map(dd => {
420
- return html`
421
- <link href="/${link_prefix && `${link_prefix}/`}${dd.src}" type="${dd.type}"
422
- rel="stylesheet"></link>`;
423
- })
424
- .join('')} `;
425
- }
426
- })()}
427
- ${d.code ?? ''}
428
- ${(() => {
429
- if (req.query.type === 'editor') {
430
- return ``;
431
- } else {
432
- return `${(data.config.globalStyle ?? [])
433
- .map((dd: any) => {
434
- try {
435
- if (dd.data.elem === 'link') {
436
- return html` <link
437
- type="text/css"
438
- rel="stylesheet"
439
- href="${dd.data.attr.find((dd: any) => {
440
- return dd.attr === 'href';
441
- }).value}"
442
- />`;
443
- }
444
- } catch (e) {
445
- return ``;
446
- }
447
- })
448
- .join('')}`;
449
- }
450
- })()}
451
- `;
452
- })(),
453
- `<script>
454
- ${[
455
- (req.query.type !== 'editor' && d.custom_script) ?? '',
456
- `window.login_config = ${JSON.stringify(login_config)};`,
457
- `window.appName = '${appName}';`,
458
- `window.glitterBase = '${brandAndMemberType.brand}';`,
459
- `window.memberType = '${brandAndMemberType.memberType}';`,
460
- `window.glitterBackend = '${config.domain}';`,
461
- `window.preloadData = ${JSON.stringify(preload)
462
- .replace(/<\/script>/g, 'sdjuescript_prepand')
463
- .replace(/<script>/g, 'sdjuescript_prefix')};`,
464
- `window.glitter_page = '${req.query.page}';`,
465
- `window.store_info = ${JSON.stringify(store_info)};`,
466
- `window.server_execute_time = ${(new Date().getTime() - start) / 1000};`,
467
- `window.language = '${language}';`,
468
- `${distribution_code}`,
469
- `window.ip_country = '${ip_country.country || 'TW'}';`,
470
- `window.currency_covert = ${JSON.stringify(await Shopping.currencyCovert((req.query.base || 'TWD') as string))};`,
471
- `window.language_list = ${JSON.stringify(language_label.label)};`,
472
- `window.home_seo=${JSON.stringify(home_seo)
473
- .replace(/<\/script>/g, 'sdjuescript_prepand')
474
- .replace(/<script>/g, 'sdjuescript_prefix')};`,
475
- ]
476
- .map(dd => {
477
- return (dd || '').trim();
478
- })
479
- .filter(dd => {
480
- return dd;
481
- })
482
- .join(';\n')}
483
- </script>
484
- ${[
485
- { src: 'glitterBundle/GlitterInitial.js', type: 'module' },
486
- { src: 'glitterBundle/module/html-generate.js', type: 'module' },
487
- { src: 'glitterBundle/html-component/widget.js', type: 'module' },
488
- { src: 'glitterBundle/plugins/trigger-event.js', type: 'module' },
489
- { src: 'api/pageConfig.js', type: 'module' },
490
- ]
491
- .map(dd => {
492
- return html` <script
493
- src="/${link_prefix && `${link_prefix}/`}${dd.src}"
494
- type="${dd.type}"
495
- ></script>`;
496
- })
497
- .join('')}
498
- ${(preload.event ?? [])
499
- .filter((dd: any) => {
500
- return dd;
501
- })
502
- .map((dd: any) => {
503
- const link = dd.fun.replace(
504
- `TriggerEvent.setEventRouter(import.meta.url, '.`,
505
- 'official_event'
506
- );
507
- return link.substring(0, link.length - 2);
508
- })
509
- .map(
510
- (dd: any) =>
511
- html` <script src="/${link_prefix && `${link_prefix}/`}${dd}" type="module"></script>`
512
- )
513
- .join('')}
514
- ${(() => {
515
- if (req.query.type === 'editor') {
516
- return ``;
517
- } else {
518
- //IOS系統必須同意後才可追蹤
519
- if((req.headers['user-agent'] as string).includes('iosGlitter') && !((req.headers['user-agent'] as string).includes('allow_track'))){
520
- customCode.ga4=[];
521
- customCode.g_tag=[];
522
- }
523
- return html`
524
- ${SeoConfig.gA4(customCode.ga4)} ${SeoConfig.gTag(customCode.g_tag)}
525
- ${seo_content
526
- .map(dd => {
527
- return dd.trim();
528
- })
529
- .join('\n')}
530
- `;
531
- }
532
- })()}`,
533
- ].join('');
534
- return {
535
- head: head,
536
- body: ``,
537
- };
538
- } else {
539
- return {
540
- head: await Seo.redirectToHomePage(appName, req),
541
- body: ``,
542
- };
543
- }
544
- } catch (e: any) {
545
- console.error(e);
546
- return {
547
- head: ``,
548
- body: `${e}`,
549
- };
550
- }
155
+ seoManager: async (req, resp)=>{
156
+ return await SeoConfig.seoDetail(dd.appName as string,req,resp)
551
157
  },
552
158
  sitemap: async (req, resp) => {
553
159
  let appName = dd.appName;
@@ -816,54 +422,7 @@ export async function createAPP(dd: any) {
816
422
  );
817
423
  }
818
424
 
819
- async function getSeoDetail(appName: string, req: any) {
820
- const sqlData = await Private_config.getConfig({
821
- appName: appName,
822
- key: 'seo_webhook',
823
- });
824
- if (!sqlData[0] || !sqlData[0].value) {
825
- return undefined;
826
- }
827
- const html = String.raw;
828
- return await db.queryLambada(
829
- {
830
- database: appName,
831
- },
832
- async db => {
833
- (db as any).execute = (db as any).query;
834
- const functionValue: { key: string; data: () => any }[] = [
835
- {
836
- key: 'db',
837
- data: () => {
838
- return db;
839
- },
840
- },
841
- {
842
- key: 'req',
843
- data: () => {
844
- return req;
845
- },
846
- },
847
- ];
848
- const evalString = `
849
- return {
850
- execute:(${functionValue
851
- .map(d2 => {
852
- return d2.key;
853
- })
854
- .join(',')})=>{
855
- try {
856
- ${sqlData[0].value.value.replace(
857
- /new\s*Promise\s*\(\s*async\s*\(\s*resolve\s*,\s*reject\s*\)\s*=>\s*\{([\s\S]*)\}\s*\)/i,
858
- 'new Promise(async (resolve, reject) => { try { $1 } catch (error) { console.log(error);reject(error); } })'
859
- )}
860
- }catch (e) { console.log(e) } } }
861
- `;
862
- const myFunction = new Function(evalString);
863
- return await myFunction().execute(functionValue[0].data(), functionValue[1].data());
864
- }
865
- );
866
- }
425
+
867
426
 
868
427
  async function getSeoSiteMap(appName: string, req: any) {
869
428
  const sqlData = await Private_config.getConfig({
@@ -1,3 +1,4 @@
1
+ import express from 'express';
1
2
  export declare class SeoConfig {
2
3
  static editorSeo: string;
3
4
  static collectionSeo(cf: {
@@ -33,6 +34,22 @@ export declare class SeoConfig {
33
34
  static fbCode(FBCode: any): string;
34
35
  static gTag(g_tag: any[]): string;
35
36
  static gA4(ga4: any[]): string;
37
+ static seoDetail(in_app: string, req: express.Request, resp: express.Response): Promise<{
38
+ head: string;
39
+ body: string;
40
+ redirect?: undefined;
41
+ seo_detail?: undefined;
42
+ } | {
43
+ redirect: string;
44
+ head?: undefined;
45
+ body?: undefined;
46
+ seo_detail?: undefined;
47
+ } | {
48
+ head: string;
49
+ body: string;
50
+ seo_detail: any;
51
+ redirect?: undefined;
52
+ }>;
36
53
  }
37
54
  export declare function extractCols(data: {
38
55
  value: any[];