@foliokit/cms-core 1.0.0 → 1.0.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 (95) hide show
  1. package/README.md +62 -2
  2. package/eslint.config.mjs +48 -0
  3. package/ng-package.json +7 -0
  4. package/package.json +5 -18
  5. package/project.json +32 -0
  6. package/{esm2022/index.js → src/index.ts} +9 -3
  7. package/src/lib/cms-core/cms-core.html +1 -0
  8. package/src/lib/cms-core/cms-core.scss +0 -0
  9. package/src/lib/cms-core/cms-core.spec.ts +44 -0
  10. package/src/lib/cms-core/cms-core.ts +9 -0
  11. package/src/lib/firebase/firebase-admin.ts +32 -0
  12. package/src/lib/firebase/firebase.config.ts +26 -0
  13. package/src/lib/firebase/firebase.providers.ts +89 -0
  14. package/src/lib/firebase/foliokit.providers.ts +178 -0
  15. package/src/lib/models/author.model.ts +16 -0
  16. package/src/lib/models/page.model.ts +11 -0
  17. package/src/lib/models/post.model.ts +41 -0
  18. package/src/lib/models/site-config.model.ts +103 -0
  19. package/src/lib/models/tag.model.ts +5 -0
  20. package/src/lib/pipes/tag-label.pipe.ts +16 -0
  21. package/src/lib/resolvers/about-page.resolver.ts +76 -0
  22. package/src/lib/resolvers/links-page.resolver.ts +77 -0
  23. package/src/lib/resolvers/posts.resolver.ts +51 -0
  24. package/src/lib/services/auth.service.ts +49 -0
  25. package/src/lib/services/author.service.ts +88 -0
  26. package/src/lib/services/post.service.spec.ts +255 -0
  27. package/src/lib/services/post.service.ts +148 -0
  28. package/src/lib/services/site-config.service.ts +86 -0
  29. package/src/lib/services/tag.service.ts +24 -0
  30. package/src/lib/tokens/post-service.token.ts +14 -0
  31. package/src/lib/tokens/site-config-service.token.ts +12 -0
  32. package/src/lib/utils/normalize-author.ts +50 -0
  33. package/src/lib/utils/normalize-post.ts +66 -0
  34. package/src/lib/utils/normalize-site-config.ts +145 -0
  35. package/testing/firestore.stub.ts +65 -0
  36. package/tsconfig.json +31 -0
  37. package/tsconfig.lib.json +12 -0
  38. package/tsconfig.lib.prod.json +9 -0
  39. package/tsconfig.spec.json +8 -0
  40. package/esm2022/foliokit-cms-core.js +0 -5
  41. package/esm2022/foliokit-cms-core.js.map +0 -1
  42. package/esm2022/index.js.map +0 -1
  43. package/esm2022/lib/firebase/firebase.config.js +0 -8
  44. package/esm2022/lib/firebase/firebase.config.js.map +0 -1
  45. package/esm2022/lib/firebase/firebase.providers.js +0 -54
  46. package/esm2022/lib/firebase/firebase.providers.js.map +0 -1
  47. package/esm2022/lib/models/author.model.js +0 -1
  48. package/esm2022/lib/models/author.model.js.map +0 -1
  49. package/esm2022/lib/models/page.model.js +0 -1
  50. package/esm2022/lib/models/page.model.js.map +0 -1
  51. package/esm2022/lib/models/post.model.js +0 -1
  52. package/esm2022/lib/models/post.model.js.map +0 -1
  53. package/esm2022/lib/models/site-config.model.js +0 -1
  54. package/esm2022/lib/models/site-config.model.js.map +0 -1
  55. package/esm2022/lib/models/tag.model.js +0 -1
  56. package/esm2022/lib/models/tag.model.js.map +0 -1
  57. package/esm2022/lib/services/auth.service.js +0 -42
  58. package/esm2022/lib/services/auth.service.js.map +0 -1
  59. package/esm2022/lib/services/page.service.js +0 -73
  60. package/esm2022/lib/services/page.service.js.map +0 -1
  61. package/esm2022/lib/services/post.service.js +0 -83
  62. package/esm2022/lib/services/post.service.js.map +0 -1
  63. package/esm2022/lib/services/site-config.service.js +0 -31
  64. package/esm2022/lib/services/site-config.service.js.map +0 -1
  65. package/esm2022/lib/services/tag.service.js +0 -22
  66. package/esm2022/lib/services/tag.service.js.map +0 -1
  67. package/esm2022/lib/tokens/page-service.token.js +0 -4
  68. package/esm2022/lib/tokens/page-service.token.js.map +0 -1
  69. package/esm2022/lib/tokens/post-service.token.js +0 -5
  70. package/esm2022/lib/tokens/post-service.token.js.map +0 -1
  71. package/esm2022/lib/utils/normalize-page.js +0 -74
  72. package/esm2022/lib/utils/normalize-page.js.map +0 -1
  73. package/esm2022/lib/utils/normalize-post.js +0 -66
  74. package/esm2022/lib/utils/normalize-post.js.map +0 -1
  75. package/esm2022/lib/utils/normalize-site-config.js +0 -62
  76. package/esm2022/lib/utils/normalize-site-config.js.map +0 -1
  77. package/foliokit-cms-core.d.ts +0 -5
  78. package/index.d.ts +0 -14
  79. package/lib/firebase/firebase.config.d.ts +0 -11
  80. package/lib/firebase/firebase.providers.d.ts +0 -3
  81. package/lib/models/author.model.d.ts +0 -14
  82. package/lib/models/page.model.d.ts +0 -40
  83. package/lib/models/post.model.d.ts +0 -39
  84. package/lib/models/site-config.model.d.ts +0 -27
  85. package/lib/models/tag.model.d.ts +0 -5
  86. package/lib/services/auth.service.d.ts +0 -13
  87. package/lib/services/page.service.d.ts +0 -15
  88. package/lib/services/post.service.d.ts +0 -17
  89. package/lib/services/site-config.service.d.ts +0 -10
  90. package/lib/services/tag.service.d.ts +0 -9
  91. package/lib/tokens/page-service.token.d.ts +0 -9
  92. package/lib/tokens/post-service.token.d.ts +0 -10
  93. package/lib/utils/normalize-page.d.ts +0 -2
  94. package/lib/utils/normalize-post.d.ts +0 -6
  95. package/lib/utils/normalize-site-config.d.ts +0 -2
@@ -1,83 +0,0 @@
1
- import { inject, Injectable } from '@angular/core';
2
- import { collection, doc, getDoc, getDocs, limit, orderBy, query, setDoc, Timestamp, updateDoc, where, } from 'firebase/firestore';
3
- import { deleteObject, ref } from 'firebase/storage';
4
- import { from, of } from 'rxjs';
5
- import { catchError, map } from 'rxjs/operators';
6
- import { FIREBASE_STORAGE, FIRESTORE } from '../firebase/firebase.config';
7
- import { normalizePost } from '../utils/normalize-post';
8
- import * as i0 from "@angular/core";
9
- export class PostService {
10
- firestore = inject(FIRESTORE);
11
- storage = inject(FIREBASE_STORAGE);
12
- getPublishedPosts() {
13
- const q = query(collection(this.firestore, 'posts'), where('status', '==', 'published'), orderBy('publishedAt', 'desc'));
14
- return from(getDocs(q)).pipe(map((snapshot) => snapshot.docs.map((d) => normalizePost({ id: d.id, ...d.data() }))), catchError((err) => {
15
- console.error('[PostService.getPublishedPosts]', err);
16
- return of([]);
17
- }));
18
- }
19
- getPostBySlug(slug) {
20
- const q = query(collection(this.firestore, 'posts'), where('status', '==', 'published'), where('slug', '==', slug), limit(1));
21
- return from(getDocs(q)).pipe(map((snapshot) => {
22
- if (snapshot.empty)
23
- return null;
24
- const d = snapshot.docs[0];
25
- return normalizePost({ id: d.id, ...d.data() });
26
- }), catchError((err) => {
27
- console.error('[PostService.getPostBySlug]', err);
28
- return of(null);
29
- }));
30
- }
31
- getPostsByTag(tag) {
32
- const q = query(collection(this.firestore, 'posts'), where('status', '==', 'published'), where('tags', 'array-contains', tag), orderBy('publishedAt', 'desc'));
33
- return from(getDocs(q)).pipe(map((snapshot) => snapshot.docs.map((d) => normalizePost({ id: d.id, ...d.data() }))), catchError((err) => {
34
- console.error('[PostService.getPostsByTag]', err);
35
- return of([]);
36
- }));
37
- }
38
- getAllPosts() {
39
- const q = query(collection(this.firestore, 'posts'), orderBy('updatedAt', 'desc'));
40
- return from(getDocs(q)).pipe(map((snapshot) => snapshot.docs.map((d) => normalizePost({ id: d.id, ...d.data() }))), catchError((err) => {
41
- console.error('[PostService.getAllPosts]', err);
42
- return of([]);
43
- }));
44
- }
45
- getPostById(id) {
46
- return from(getDoc(doc(this.firestore, 'posts', id))).pipe(map((snapshot) => {
47
- if (!snapshot.exists())
48
- throw new Error(`Post not found: ${id}`);
49
- return normalizePost({ id: snapshot.id, ...snapshot.data() });
50
- }));
51
- }
52
- deleteStorageFile(storagePath) {
53
- const fileRef = ref(this.storage, storagePath);
54
- return from(deleteObject(fileRef));
55
- }
56
- savePost(post) {
57
- const nowMs = Date.now();
58
- const nowTs = Timestamp.fromMillis(nowMs);
59
- if (post.id === '') {
60
- const newId = doc(collection(this.firestore, 'posts')).id;
61
- const savedPost = { ...post, id: newId, createdAt: nowMs, updatedAt: nowMs };
62
- // Write Timestamp objects to Firestore for proper ordering/querying
63
- const firestorePayload = { ...savedPost, createdAt: nowTs, updatedAt: nowTs };
64
- return from(setDoc(doc(this.firestore, 'posts', newId), firestorePayload)).pipe(map(() => savedPost), catchError((err) => {
65
- console.error('[PostService.savePost/create]', err);
66
- throw err;
67
- }));
68
- }
69
- const savedPost = { ...post, updatedAt: nowMs };
70
- const firestorePayload = { ...savedPost, updatedAt: nowTs };
71
- return from(updateDoc(doc(this.firestore, 'posts', post.id), firestorePayload)).pipe(map(() => savedPost), catchError((err) => {
72
- console.error('[PostService.savePost/update]', err);
73
- throw err;
74
- }));
75
- }
76
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PostService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
77
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PostService, providedIn: 'root' });
78
- }
79
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: PostService, decorators: [{
80
- type: Injectable,
81
- args: [{ providedIn: 'root' }]
82
- }] });
83
- //# sourceMappingURL=post.service.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"post.service.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/services/post.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { inject, Injectable } from '@angular/core';\nimport {\n collection,\n doc,\n getDoc,\n getDocs,\n limit,\n orderBy,\n query,\n setDoc,\n Timestamp,\n updateDoc,\n where,\n} from 'firebase/firestore';\nimport { deleteObject, ref } from 'firebase/storage';\nimport { from, Observable, of } from 'rxjs';\nimport { catchError, map } from 'rxjs/operators';\nimport { FIREBASE_STORAGE, FIRESTORE } from '../firebase/firebase.config';\nimport type { BlogPost } from '../models/post.model';\nimport { normalizePost } from '../utils/normalize-post';\nimport type { IBlogPostService } from '../tokens/post-service.token';\n\n@Injectable({ providedIn: 'root' })\nexport class PostService implements IBlogPostService {\n private readonly firestore = inject(FIRESTORE);\n private readonly storage = inject(FIREBASE_STORAGE);\n\n getPublishedPosts(): Observable<BlogPost[]> {\n const q = query(\n collection(this.firestore, 'posts'),\n where('status', '==', 'published'),\n orderBy('publishedAt', 'desc'),\n );\n return from(getDocs(q)).pipe(\n map((snapshot) =>\n snapshot.docs.map((d) => normalizePost({ id: d.id, ...d.data() })),\n ),\n catchError((err) => {\n console.error('[PostService.getPublishedPosts]', err);\n return of([]);\n }),\n );\n }\n\n getPostBySlug(slug: string): Observable<BlogPost | null> {\n const q = query(\n collection(this.firestore, 'posts'),\n where('status', '==', 'published'),\n where('slug', '==', slug),\n limit(1),\n );\n return from(getDocs(q)).pipe(\n map((snapshot) => {\n if (snapshot.empty) return null;\n const d = snapshot.docs[0];\n return normalizePost({ id: d.id, ...d.data() });\n }),\n catchError((err) => {\n console.error('[PostService.getPostBySlug]', err);\n return of(null);\n }),\n );\n }\n\n getPostsByTag(tag: string): Observable<BlogPost[]> {\n const q = query(\n collection(this.firestore, 'posts'),\n where('status', '==', 'published'),\n where('tags', 'array-contains', tag),\n orderBy('publishedAt', 'desc'),\n );\n return from(getDocs(q)).pipe(\n map((snapshot) =>\n snapshot.docs.map((d) => normalizePost({ id: d.id, ...d.data() })),\n ),\n catchError((err) => {\n console.error('[PostService.getPostsByTag]', err);\n return of([]);\n }),\n );\n }\n\n getAllPosts(): Observable<BlogPost[]> {\n const q = query(\n collection(this.firestore, 'posts'),\n orderBy('updatedAt', 'desc'),\n );\n return from(getDocs(q)).pipe(\n map((snapshot) =>\n snapshot.docs.map((d) => normalizePost({ id: d.id, ...d.data() })),\n ),\n catchError((err) => {\n console.error('[PostService.getAllPosts]', err);\n return of([]);\n }),\n );\n }\n\n getPostById(id: string): Observable<BlogPost> {\n return from(getDoc(doc(this.firestore, 'posts', id))).pipe(\n map((snapshot) => {\n if (!snapshot.exists()) throw new Error(`Post not found: ${id}`);\n return normalizePost({ id: snapshot.id, ...snapshot.data() });\n }),\n );\n }\n\n deleteStorageFile(storagePath: string): Observable<void> {\n const fileRef = ref(this.storage, storagePath);\n return from(deleteObject(fileRef));\n }\n\n savePost(post: BlogPost): Observable<BlogPost> {\n const nowMs = Date.now();\n const nowTs = Timestamp.fromMillis(nowMs);\n\n if (post.id === '') {\n const newId = doc(collection(this.firestore, 'posts')).id;\n const savedPost: BlogPost = { ...post, id: newId, createdAt: nowMs, updatedAt: nowMs };\n // Write Timestamp objects to Firestore for proper ordering/querying\n const firestorePayload = { ...savedPost, createdAt: nowTs, updatedAt: nowTs };\n return from(\n setDoc(doc(this.firestore, 'posts', newId), firestorePayload),\n ).pipe(\n map(() => savedPost),\n catchError((err) => {\n console.error('[PostService.savePost/create]', err);\n throw err;\n }),\n );\n }\n\n const savedPost: BlogPost = { ...post, updatedAt: nowMs };\n const firestorePayload = { ...savedPost, updatedAt: nowTs };\n return from(\n updateDoc(doc(this.firestore, 'posts', post.id), firestorePayload),\n ).pipe(\n map(() => savedPost),\n catchError((err) => {\n console.error('[PostService.savePost/update]', err);\n throw err;\n }),\n );\n }\n}\n"]}
@@ -1,31 +0,0 @@
1
- import { inject, Injectable } from '@angular/core';
2
- import { doc, getDoc } from 'firebase/firestore';
3
- import { from, of } from 'rxjs';
4
- import { catchError, map } from 'rxjs/operators';
5
- import { FIRESTORE } from '../firebase/firebase.config';
6
- import { normalizeSiteConfig } from '../utils/normalize-site-config';
7
- import * as i0 from "@angular/core";
8
- export class SiteConfigService {
9
- firestore = inject(FIRESTORE);
10
- getSiteConfig(siteId) {
11
- const ref = doc(this.firestore, 'site-config', siteId);
12
- return from(getDoc(ref)).pipe(map((snap) => {
13
- if (!snap.exists())
14
- return null;
15
- return normalizeSiteConfig({ id: snap.id, ...snap.data() });
16
- }), catchError((err) => {
17
- console.error('[SiteConfigService.getSiteConfig]', err);
18
- return of(null);
19
- }));
20
- }
21
- getDefaultSiteConfig() {
22
- return this.getSiteConfig('default');
23
- }
24
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SiteConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
25
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SiteConfigService, providedIn: 'root' });
26
- }
27
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SiteConfigService, decorators: [{
28
- type: Injectable,
29
- args: [{ providedIn: 'root' }]
30
- }] });
31
- //# sourceMappingURL=site-config.service.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"site-config.service.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/services/site-config.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAc,EAAE,EAAE,MAAM,MAAM,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAExD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;;AAGrE,MAAM,OAAO,iBAAiB;IACX,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAE/C,aAAa,CAAC,MAAc;QAC1B,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAC3B,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACX,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;gBAAE,OAAO,IAAI,CAAC;YAChC,OAAO,mBAAmB,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9D,CAAC,CAAC,EACF,UAAU,CAAC,CAAC,GAAG,EAAE,EAAE;YACjB,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;YACxD,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;IAED,oBAAoB;QAClB,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;uGAnBU,iBAAiB;2GAAjB,iBAAiB,cADJ,MAAM;;2FACnB,iBAAiB;kBAD7B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE","sourcesContent":["import { inject, Injectable } from '@angular/core';\nimport { doc, getDoc } from 'firebase/firestore';\nimport { from, Observable, of } from 'rxjs';\nimport { catchError, map } from 'rxjs/operators';\nimport { FIRESTORE } from '../firebase/firebase.config';\nimport type { SiteConfig } from '../models/site-config.model';\nimport { normalizeSiteConfig } from '../utils/normalize-site-config';\n\n@Injectable({ providedIn: 'root' })\nexport class SiteConfigService {\n private readonly firestore = inject(FIRESTORE);\n\n getSiteConfig(siteId: string): Observable<SiteConfig | null> {\n const ref = doc(this.firestore, 'site-config', siteId);\n return from(getDoc(ref)).pipe(\n map((snap) => {\n if (!snap.exists()) return null;\n return normalizeSiteConfig({ id: snap.id, ...snap.data() });\n }),\n catchError((err) => {\n console.error('[SiteConfigService.getSiteConfig]', err);\n return of(null);\n }),\n );\n }\n\n getDefaultSiteConfig(): Observable<SiteConfig | null> {\n return this.getSiteConfig('default');\n }\n}\n"]}
@@ -1,22 +0,0 @@
1
- import { inject, Injectable } from '@angular/core';
2
- import { collection, getDocs } from 'firebase/firestore';
3
- import { from, of } from 'rxjs';
4
- import { catchError, map } from 'rxjs/operators';
5
- import { FIRESTORE } from '../firebase/firebase.config';
6
- import * as i0 from "@angular/core";
7
- export class TagService {
8
- firestore = inject(FIRESTORE);
9
- getAllTags() {
10
- return from(getDocs(collection(this.firestore, 'tags'))).pipe(map((snapshot) => snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }))), catchError((err) => {
11
- console.error('[TagService.getAllTags]', err);
12
- return of([]);
13
- }));
14
- }
15
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TagService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
16
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TagService, providedIn: 'root' });
17
- }
18
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TagService, decorators: [{
19
- type: Injectable,
20
- args: [{ providedIn: 'root' }]
21
- }] });
22
- //# sourceMappingURL=tag.service.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tag.service.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/services/tag.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAc,EAAE,EAAE,MAAM,MAAM,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;;AAIxD,MAAM,OAAO,UAAU;IACJ,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAE/C,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAC3D,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CACf,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,CAAQ,CAAC,CACnE,EACD,UAAU,CAAC,CAAC,GAAG,EAAE,EAAE;YACjB,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;YAC9C,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QAChB,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;uGAbU,UAAU;2GAAV,UAAU,cADG,MAAM;;2FACnB,UAAU;kBADtB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE","sourcesContent":["import { inject, Injectable } from '@angular/core';\nimport { collection, getDocs } from 'firebase/firestore';\nimport { from, Observable, of } from 'rxjs';\nimport { catchError, map } from 'rxjs/operators';\nimport { FIRESTORE } from '../firebase/firebase.config';\nimport type { Tag } from '../models/tag.model';\n\n@Injectable({ providedIn: 'root' })\nexport class TagService {\n private readonly firestore = inject(FIRESTORE);\n\n getAllTags(): Observable<Tag[]> {\n return from(getDocs(collection(this.firestore, 'tags'))).pipe(\n map((snapshot) =>\n snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }) as Tag),\n ),\n catchError((err) => {\n console.error('[TagService.getAllTags]', err);\n return of([]);\n }),\n );\n }\n}\n"]}
@@ -1,4 +0,0 @@
1
- import { InjectionToken, makeStateKey } from '@angular/core';
2
- export const BLOG_PAGE_SERVICE = new InjectionToken('BLOG_PAGE_SERVICE');
3
- export const PAGE_TRANSFER_KEY = makeStateKey('cms-page');
4
- //# sourceMappingURL=page-service.token.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"page-service.token.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/tokens/page-service.token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAS7D,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,cAAc,CACjD,mBAAmB,CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAsB,UAAU,CAAC,CAAC","sourcesContent":["import { InjectionToken, makeStateKey } from '@angular/core';\nimport type { Observable } from 'rxjs';\nimport type { CmsPageUnion } from '../models/page.model';\n\nexport interface IPageService {\n getPageBySlug(slug: string): Observable<CmsPageUnion | null>;\n getPageById(id: string): Observable<CmsPageUnion | null>;\n}\n\nexport const BLOG_PAGE_SERVICE = new InjectionToken<IPageService>(\n 'BLOG_PAGE_SERVICE',\n);\n\nexport const PAGE_TRANSFER_KEY = makeStateKey<CmsPageUnion | null>('cms-page');\n"]}
@@ -1,5 +0,0 @@
1
- import { InjectionToken, makeStateKey } from '@angular/core';
2
- export const BLOG_POST_SERVICE = new InjectionToken('BLOG_POST_SERVICE');
3
- export const POST_TRANSFER_KEY = makeStateKey('blog-post');
4
- export const POSTS_TRANSFER_KEY = makeStateKey('blog-posts');
5
- //# sourceMappingURL=post-service.token.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"post-service.token.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/tokens/post-service.token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAS7D,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,cAAc,CACjD,mBAAmB,CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAkB,WAAW,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAa,YAAY,CAAC,CAAC","sourcesContent":["import { InjectionToken, makeStateKey } from '@angular/core';\nimport type { Observable } from 'rxjs';\nimport type { BlogPost } from '../models/post.model';\n\nexport interface IBlogPostService {\n getPublishedPosts(): Observable<BlogPost[]>;\n getPostBySlug(slug: string): Observable<BlogPost | null>;\n}\n\nexport const BLOG_POST_SERVICE = new InjectionToken<IBlogPostService>(\n 'BLOG_POST_SERVICE',\n);\n\nexport const POST_TRANSFER_KEY = makeStateKey<BlogPost | null>('blog-post');\nexport const POSTS_TRANSFER_KEY = makeStateKey<BlogPost[]>('blog-posts');\n"]}
@@ -1,74 +0,0 @@
1
- function normalizeTimestamp(value) {
2
- if (value == null)
3
- return 0;
4
- if (typeof value === 'number')
5
- return value;
6
- if (value instanceof Date)
7
- return value.getTime();
8
- if (typeof value === 'object') {
9
- const v = value;
10
- if (typeof v.toMillis === 'function') {
11
- return v.toMillis();
12
- }
13
- if (typeof v.toDate === 'function') {
14
- return v.toDate().getTime();
15
- }
16
- if (typeof v['_seconds'] === 'number') {
17
- return v['_seconds'] * 1000 +
18
- Math.floor((v['_nanoseconds'] ?? 0) / 1e6);
19
- }
20
- if (typeof v['seconds'] === 'number') {
21
- return v['seconds'] * 1000 +
22
- Math.floor((v['nanoseconds'] ?? 0) / 1e6);
23
- }
24
- }
25
- return 0;
26
- }
27
- function normalizeLinks(raw) {
28
- if (!Array.isArray(raw))
29
- return [];
30
- return raw.map((l, i) => ({
31
- id: l['id'] ?? crypto.randomUUID(),
32
- label: l['label'] ?? '',
33
- url: l['url'] ?? '',
34
- icon: l['icon'],
35
- platform: l['platform'],
36
- highlighted: l['highlighted'],
37
- order: typeof l['order'] === 'number' ? l['order'] : i,
38
- }));
39
- }
40
- export function normalizePage(raw) {
41
- const type = raw['type'];
42
- const base = {
43
- id: raw['id'] ?? '',
44
- slug: raw['slug'] ?? '',
45
- title: raw['title'] ?? '',
46
- status: raw['status'] ?? 'draft',
47
- seo: raw['seo'] ?? {},
48
- updatedAt: normalizeTimestamp(raw['updatedAt']),
49
- createdAt: normalizeTimestamp(raw['createdAt']),
50
- };
51
- if (type === 'links') {
52
- const page = {
53
- ...base,
54
- type: 'links',
55
- avatarUrl: raw['avatarUrl'],
56
- avatarAlt: raw['avatarAlt'],
57
- headline: raw['headline'],
58
- bio: raw['bio'],
59
- links: normalizeLinks(raw['links']),
60
- };
61
- return page;
62
- }
63
- const page = {
64
- ...base,
65
- type: 'about',
66
- heroImageUrl: raw['heroImageUrl'],
67
- heroImageAlt: raw['heroImageAlt'],
68
- body: raw['body'] ?? '',
69
- contentVersion: raw['contentVersion'] ?? 1,
70
- embeddedMedia: raw['embeddedMedia'] ?? {},
71
- };
72
- return page;
73
- }
74
- //# sourceMappingURL=normalize-page.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"normalize-page.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/utils/normalize-page.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AboutPage, CmsPageUnion, LinksPage, LinksLink } from '../models/page.model';\n\nfunction normalizeTimestamp(value: unknown): number {\n if (value == null) return 0;\n if (typeof value === 'number') return value;\n if (value instanceof Date) return value.getTime();\n if (typeof value === 'object') {\n const v = value as Record<string, unknown>;\n if (typeof (v as { toMillis?: unknown }).toMillis === 'function') {\n return (v as { toMillis(): number }).toMillis();\n }\n if (typeof (v as { toDate?: unknown }).toDate === 'function') {\n return (v as { toDate(): Date }).toDate().getTime();\n }\n if (typeof v['_seconds'] === 'number') {\n return (v['_seconds'] as number) * 1000 +\n Math.floor(((v['_nanoseconds'] as number) ?? 0) / 1e6);\n }\n if (typeof v['seconds'] === 'number') {\n return (v['seconds'] as number) * 1000 +\n Math.floor(((v['nanoseconds'] as number) ?? 0) / 1e6);\n }\n }\n return 0;\n}\n\nfunction normalizeLinks(raw: unknown): LinksLink[] {\n if (!Array.isArray(raw)) return [];\n return (raw as Record<string, unknown>[]).map((l, i) => ({\n id: (l['id'] as string) ?? crypto.randomUUID(),\n label: (l['label'] as string) ?? '',\n url: (l['url'] as string) ?? '',\n icon: l['icon'] as string | undefined,\n platform: l['platform'] as LinksLink['platform'],\n highlighted: l['highlighted'] as boolean | undefined,\n order: typeof l['order'] === 'number' ? (l['order'] as number) : i,\n }));\n}\n\nexport function normalizePage(raw: Record<string, unknown>): CmsPageUnion {\n const type = raw['type'] as string;\n const base = {\n id: (raw['id'] as string) ?? '',\n slug: (raw['slug'] as string) ?? '',\n title: (raw['title'] as string) ?? '',\n status: (raw['status'] as CmsPageUnion['status']) ?? 'draft',\n seo: (raw['seo'] as CmsPageUnion['seo']) ?? {},\n updatedAt: normalizeTimestamp(raw['updatedAt']),\n createdAt: normalizeTimestamp(raw['createdAt']),\n };\n\n if (type === 'links') {\n const page: LinksPage = {\n ...base,\n type: 'links',\n avatarUrl: raw['avatarUrl'] as string | undefined,\n avatarAlt: raw['avatarAlt'] as string | undefined,\n headline: raw['headline'] as string | undefined,\n bio: raw['bio'] as string | undefined,\n links: normalizeLinks(raw['links']),\n };\n return page;\n }\n\n const page: AboutPage = {\n ...base,\n type: 'about',\n heroImageUrl: raw['heroImageUrl'] as string | undefined,\n heroImageAlt: raw['heroImageAlt'] as string | undefined,\n body: (raw['body'] as string) ?? '',\n contentVersion: (raw['contentVersion'] as number) ?? 1,\n embeddedMedia: (raw['embeddedMedia'] as AboutPage['embeddedMedia']) ?? {},\n };\n return page;\n}\n"]}
@@ -1,66 +0,0 @@
1
- /**
2
- * Converts a Firestore timestamp in any of its runtime forms to milliseconds.
3
- *
4
- * Handles:
5
- * - Native Timestamp objects from either SDK (have .toMillis())
6
- * - Objects with .toDate() method (client SDK Timestamp without .toMillis())
7
- * - Admin SDK serialized form { _seconds, _nanoseconds }
8
- * - Plain { seconds, nanoseconds } objects
9
- * - Already-numeric millisecond values
10
- * - JavaScript Date objects
11
- */
12
- function normalizeTimestamp(value) {
13
- if (value == null)
14
- return 0;
15
- if (typeof value === 'number')
16
- return value;
17
- if (value instanceof Date)
18
- return value.getTime();
19
- if (typeof value === 'object') {
20
- const v = value;
21
- if (typeof v.toMillis === 'function') {
22
- return v.toMillis();
23
- }
24
- if (typeof v.toDate === 'function') {
25
- return v.toDate().getTime();
26
- }
27
- if (typeof v['_seconds'] === 'number') {
28
- return v['_seconds'] * 1000 +
29
- Math.floor((v['_nanoseconds'] ?? 0) / 1e6);
30
- }
31
- if (typeof v['seconds'] === 'number') {
32
- return v['seconds'] * 1000 +
33
- Math.floor((v['nanoseconds'] ?? 0) / 1e6);
34
- }
35
- }
36
- return 0;
37
- }
38
- /**
39
- * Maps raw Firestore DocumentData (merged with its doc id) into a fully typed,
40
- * TransferState-serializable BlogPost. Callers must pass { id: doc.id, ...doc.data() }.
41
- */
42
- export function normalizePost(raw) {
43
- return {
44
- id: raw['id'] ?? '',
45
- slug: raw['slug'] ?? '',
46
- title: raw['title'] ?? '',
47
- subtitle: raw['subtitle'],
48
- status: raw['status'],
49
- content: raw['content'] ?? '',
50
- excerpt: raw['excerpt'],
51
- thumbnailUrl: raw['thumbnailUrl'],
52
- thumbnailAlt: raw['thumbnailAlt'],
53
- tags: raw['tags'] ?? [],
54
- authorId: raw['authorId'],
55
- readingTimeMinutes: raw['readingTimeMinutes'],
56
- embeddedMedia: raw['embeddedMedia'] ?? {},
57
- seo: raw['seo'] ?? {},
58
- publishedAt: normalizeTimestamp(raw['publishedAt']),
59
- scheduledPublishAt: raw['scheduledPublishAt'] != null
60
- ? normalizeTimestamp(raw['scheduledPublishAt'])
61
- : undefined,
62
- updatedAt: normalizeTimestamp(raw['updatedAt']),
63
- createdAt: normalizeTimestamp(raw['createdAt']),
64
- };
65
- }
66
- //# sourceMappingURL=normalize-post.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"normalize-post.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/utils/normalize-post.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,CAAC,CAAC;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,KAAgC,CAAC;QAC3C,IAAI,OAAQ,CAA4B,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;YACjE,OAAQ,CAA4B,CAAC,QAAQ,EAAE,CAAC;QAClD,CAAC;QACD,IAAI,OAAQ,CAA0B,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC7D,OAAQ,CAAwB,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;QACtD,CAAC;QACD,IAAI,OAAO,CAAC,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE,CAAC;YACtC,OAAQ,CAAC,CAAC,UAAU,CAAY,GAAG,IAAI;gBACrC,IAAI,CAAC,KAAK,CAAC,CAAE,CAAC,CAAC,cAAc,CAAY,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,QAAQ,EAAE,CAAC;YACrC,OAAQ,CAAC,CAAC,SAAS,CAAY,GAAG,IAAI;gBACpC,IAAI,CAAC,KAAK,CAAC,CAAE,CAAC,CAAC,aAAa,CAAY,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAA4B;IACxD,OAAO;QACL,EAAE,EAAG,GAAG,CAAC,IAAI,CAAY,IAAI,EAAE;QAC/B,IAAI,EAAG,GAAG,CAAC,MAAM,CAAY,IAAI,EAAE;QACnC,KAAK,EAAG,GAAG,CAAC,OAAO,CAAY,IAAI,EAAE;QACrC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAuB;QAC/C,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAuB;QAC3C,OAAO,EAAG,GAAG,CAAC,SAAS,CAAY,IAAI,EAAE;QACzC,OAAO,EAAE,GAAG,CAAC,SAAS,CAAuB;QAC7C,YAAY,EAAE,GAAG,CAAC,cAAc,CAAuB;QACvD,YAAY,EAAE,GAAG,CAAC,cAAc,CAAuB;QACvD,IAAI,EAAG,GAAG,CAAC,MAAM,CAAc,IAAI,EAAE;QACrC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAuB;QAC/C,kBAAkB,EAAE,GAAG,CAAC,oBAAoB,CAAuB;QACnE,aAAa,EAAG,GAAG,CAAC,eAAe,CAA+B,IAAI,EAAE;QACxE,GAAG,EAAG,GAAG,CAAC,KAAK,CAAqB,IAAI,EAAE;QAC1C,WAAW,EAAE,kBAAkB,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACnD,kBAAkB,EAChB,GAAG,CAAC,oBAAoB,CAAC,IAAI,IAAI;YAC/B,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;YAC/C,CAAC,CAAC,SAAS;QACf,SAAS,EAAE,kBAAkB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/C,SAAS,EAAE,kBAAkB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;KAChD,CAAC;AACJ,CAAC","sourcesContent":["import type { BlogPost } from '../models/post.model';\n\n/**\n * Converts a Firestore timestamp in any of its runtime forms to milliseconds.\n *\n * Handles:\n * - Native Timestamp objects from either SDK (have .toMillis())\n * - Objects with .toDate() method (client SDK Timestamp without .toMillis())\n * - Admin SDK serialized form { _seconds, _nanoseconds }\n * - Plain { seconds, nanoseconds } objects\n * - Already-numeric millisecond values\n * - JavaScript Date objects\n */\nfunction normalizeTimestamp(value: unknown): number {\n if (value == null) return 0;\n if (typeof value === 'number') return value;\n if (value instanceof Date) return value.getTime();\n if (typeof value === 'object') {\n const v = value as Record<string, unknown>;\n if (typeof (v as { toMillis?: unknown }).toMillis === 'function') {\n return (v as { toMillis(): number }).toMillis();\n }\n if (typeof (v as { toDate?: unknown }).toDate === 'function') {\n return (v as { toDate(): Date }).toDate().getTime();\n }\n if (typeof v['_seconds'] === 'number') {\n return (v['_seconds'] as number) * 1000 +\n Math.floor(((v['_nanoseconds'] as number) ?? 0) / 1e6);\n }\n if (typeof v['seconds'] === 'number') {\n return (v['seconds'] as number) * 1000 +\n Math.floor(((v['nanoseconds'] as number) ?? 0) / 1e6);\n }\n }\n return 0;\n}\n\n/**\n * Maps raw Firestore DocumentData (merged with its doc id) into a fully typed,\n * TransferState-serializable BlogPost. Callers must pass { id: doc.id, ...doc.data() }.\n */\nexport function normalizePost(raw: Record<string, unknown>): BlogPost {\n return {\n id: (raw['id'] as string) ?? '',\n slug: (raw['slug'] as string) ?? '',\n title: (raw['title'] as string) ?? '',\n subtitle: raw['subtitle'] as string | undefined,\n status: raw['status'] as BlogPost['status'],\n content: (raw['content'] as string) ?? '',\n excerpt: raw['excerpt'] as string | undefined,\n thumbnailUrl: raw['thumbnailUrl'] as string | undefined,\n thumbnailAlt: raw['thumbnailAlt'] as string | undefined,\n tags: (raw['tags'] as string[]) ?? [],\n authorId: raw['authorId'] as string | undefined,\n readingTimeMinutes: raw['readingTimeMinutes'] as number | undefined,\n embeddedMedia: (raw['embeddedMedia'] as BlogPost['embeddedMedia']) ?? {},\n seo: (raw['seo'] as BlogPost['seo']) ?? {},\n publishedAt: normalizeTimestamp(raw['publishedAt']),\n scheduledPublishAt:\n raw['scheduledPublishAt'] != null\n ? normalizeTimestamp(raw['scheduledPublishAt'])\n : undefined,\n updatedAt: normalizeTimestamp(raw['updatedAt']),\n createdAt: normalizeTimestamp(raw['createdAt']),\n };\n}\n"]}
@@ -1,62 +0,0 @@
1
- function normalizeTimestamp(value) {
2
- if (value == null)
3
- return 0;
4
- if (typeof value === 'number')
5
- return value;
6
- if (value instanceof Date)
7
- return value.getTime();
8
- if (typeof value === 'object') {
9
- const v = value;
10
- if (typeof v.toMillis === 'function') {
11
- return v.toMillis();
12
- }
13
- if (typeof v.toDate === 'function') {
14
- return v.toDate().getTime();
15
- }
16
- if (typeof v['_seconds'] === 'number') {
17
- return v['_seconds'] * 1000 +
18
- Math.floor((v['_nanoseconds'] ?? 0) / 1e6);
19
- }
20
- if (typeof v['seconds'] === 'number') {
21
- return v['seconds'] * 1000 +
22
- Math.floor((v['nanoseconds'] ?? 0) / 1e6);
23
- }
24
- }
25
- return 0;
26
- }
27
- function normalizeNavItems(raw) {
28
- if (!Array.isArray(raw))
29
- return [];
30
- return raw.map((item) => ({
31
- label: item['label'] ?? '',
32
- url: item['url'] ?? '',
33
- order: item['order'],
34
- external: item['external'],
35
- icon: item['icon'],
36
- }));
37
- }
38
- function normalizeSocialLinks(raw) {
39
- if (!Array.isArray(raw))
40
- return [];
41
- return raw.map((item) => ({
42
- platform: item['platform'],
43
- url: item['url'] ?? '',
44
- label: item['label'],
45
- icon: item['icon'],
46
- }));
47
- }
48
- export function normalizeSiteConfig(raw) {
49
- return {
50
- id: raw['id'] ?? '',
51
- siteName: raw['siteName'] ?? '',
52
- siteUrl: raw['siteUrl'] ?? '',
53
- description: raw['description'],
54
- logo: raw['logo'],
55
- favicon: raw['favicon'],
56
- nav: normalizeNavItems(raw['nav']),
57
- social: normalizeSocialLinks(raw['social']),
58
- defaultAuthorId: raw['defaultAuthorId'],
59
- updatedAt: normalizeTimestamp(raw['updatedAt']),
60
- };
61
- }
62
- //# sourceMappingURL=normalize-site-config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"normalize-site-config.js","sourceRoot":"","sources":["../../../../../../libs/cms-core/src/lib/utils/normalize-site-config.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SiteConfig } from '../models/site-config.model';\nimport type { NavItem, SocialLink, SocialPlatform } from '../models/site-config.model';\n\nfunction normalizeTimestamp(value: unknown): number {\n if (value == null) return 0;\n if (typeof value === 'number') return value;\n if (value instanceof Date) return value.getTime();\n if (typeof value === 'object') {\n const v = value as Record<string, unknown>;\n if (typeof (v as { toMillis?: unknown }).toMillis === 'function') {\n return (v as { toMillis(): number }).toMillis();\n }\n if (typeof (v as { toDate?: unknown }).toDate === 'function') {\n return (v as { toDate(): Date }).toDate().getTime();\n }\n if (typeof v['_seconds'] === 'number') {\n return (v['_seconds'] as number) * 1000 +\n Math.floor(((v['_nanoseconds'] as number) ?? 0) / 1e6);\n }\n if (typeof v['seconds'] === 'number') {\n return (v['seconds'] as number) * 1000 +\n Math.floor(((v['nanoseconds'] as number) ?? 0) / 1e6);\n }\n }\n return 0;\n}\n\nfunction normalizeNavItems(raw: unknown): NavItem[] {\n if (!Array.isArray(raw)) return [];\n return (raw as Record<string, unknown>[]).map((item) => ({\n label: (item['label'] as string) ?? '',\n url: (item['url'] as string) ?? '',\n order: item['order'] as number | undefined,\n external: item['external'] as boolean | undefined,\n icon: item['icon'] as string | undefined,\n }));\n}\n\nfunction normalizeSocialLinks(raw: unknown): SocialLink[] {\n if (!Array.isArray(raw)) return [];\n return (raw as Record<string, unknown>[]).map((item) => ({\n platform: item['platform'] as SocialPlatform,\n url: (item['url'] as string) ?? '',\n label: item['label'] as string | undefined,\n icon: item['icon'] as string | undefined,\n }));\n}\n\nexport function normalizeSiteConfig(raw: Record<string, unknown>): SiteConfig {\n return {\n id: (raw['id'] as string) ?? '',\n siteName: (raw['siteName'] as string) ?? '',\n siteUrl: (raw['siteUrl'] as string) ?? '',\n description: raw['description'] as string | undefined,\n logo: raw['logo'] as string | undefined,\n favicon: raw['favicon'] as string | undefined,\n nav: normalizeNavItems(raw['nav']),\n social: normalizeSocialLinks(raw['social']),\n defaultAuthorId: raw['defaultAuthorId'] as string | undefined,\n updatedAt: normalizeTimestamp(raw['updatedAt']),\n };\n}\n"]}
@@ -1,5 +0,0 @@
1
- /**
2
- * Generated bundle index. Do not edit.
3
- */
4
- /// <amd-module name="@foliokit/cms-core" />
5
- export * from './index';
package/index.d.ts DELETED
@@ -1,14 +0,0 @@
1
- export * from './lib/firebase/firebase.config';
2
- export * from './lib/firebase/firebase.providers';
3
- export * from './lib/models/post.model';
4
- export * from './lib/models/site-config.model';
5
- export * from './lib/models/page.model';
6
- export * from './lib/models/tag.model';
7
- export * from './lib/models/author.model';
8
- export * from './lib/services/auth.service';
9
- export * from './lib/services/post.service';
10
- export * from './lib/services/page.service';
11
- export * from './lib/services/site-config.service';
12
- export * from './lib/services/tag.service';
13
- export * from './lib/tokens/post-service.token';
14
- export * from './lib/tokens/page-service.token';
@@ -1,11 +0,0 @@
1
- import { InjectionToken } from '@angular/core';
2
- import type { FirebaseApp, FirebaseOptions } from 'firebase/app';
3
- import type { Firestore } from 'firebase/firestore';
4
- import type { FirebaseStorage } from 'firebase/storage';
5
- import type { Auth } from 'firebase/auth';
6
- export declare const FIREBASE_OPTIONS: InjectionToken<FirebaseOptions>;
7
- export declare const FIREBASE_APP: InjectionToken<FirebaseApp>;
8
- export declare const FIRESTORE: InjectionToken<Firestore>;
9
- export declare const FIREBASE_STORAGE: InjectionToken<FirebaseStorage>;
10
- export declare const FIREBASE_AUTH: InjectionToken<Auth | null>;
11
- export declare const ADMIN_EMAIL: InjectionToken<string>;
@@ -1,3 +0,0 @@
1
- import { EnvironmentProviders } from '@angular/core';
2
- import { FirebaseOptions } from 'firebase/app';
3
- export declare function provideFirebase(options: FirebaseOptions, useEmulator?: boolean): EnvironmentProviders;
@@ -1,14 +0,0 @@
1
- import type { SocialLink } from './site-config.model';
2
- export interface Author {
3
- id: string;
4
- name: string;
5
- slug: string;
6
- bio?: string;
7
- avatarUrl?: string;
8
- email?: string;
9
- social?: SocialLink[];
10
- /** Unix milliseconds. */
11
- createdAt: number;
12
- /** Unix milliseconds. */
13
- updatedAt: number;
14
- }
@@ -1,40 +0,0 @@
1
- import type { SeoMeta, EmbeddedMediaEntry } from './post.model';
2
- import type { SocialPlatform } from './site-config.model';
3
- export interface CmsPageBase {
4
- id: string;
5
- type: 'about' | 'links';
6
- slug: string;
7
- title: string;
8
- status: 'draft' | 'published';
9
- seo: SeoMeta;
10
- /** Unix milliseconds — same convention as BlogPost. */
11
- updatedAt: number;
12
- /** Unix milliseconds. */
13
- createdAt: number;
14
- }
15
- export interface AboutPage extends CmsPageBase {
16
- type: 'about';
17
- heroImageUrl?: string;
18
- heroImageAlt?: string;
19
- body: string;
20
- contentVersion: number;
21
- embeddedMedia: Record<string, EmbeddedMediaEntry>;
22
- }
23
- export interface LinksLink {
24
- id: string;
25
- label: string;
26
- url: string;
27
- icon?: string;
28
- platform?: SocialPlatform;
29
- highlighted?: boolean;
30
- order: number;
31
- }
32
- export interface LinksPage extends CmsPageBase {
33
- type: 'links';
34
- avatarUrl?: string;
35
- avatarAlt?: string;
36
- headline?: string;
37
- bio?: string;
38
- links: LinksLink[];
39
- }
40
- export type CmsPageUnion = AboutPage | LinksPage;
@@ -1,39 +0,0 @@
1
- export interface SeoMeta {
2
- title?: string;
3
- description?: string;
4
- keywords?: string[];
5
- ogImage?: string;
6
- canonicalUrl?: string;
7
- noIndex?: boolean;
8
- }
9
- export interface EmbeddedMediaEntry {
10
- token: string;
11
- storagePath: string;
12
- downloadUrl: string;
13
- alt: string;
14
- mimeType: string;
15
- }
16
- export interface BlogPost {
17
- id: string;
18
- slug: string;
19
- title: string;
20
- subtitle?: string;
21
- status: 'published' | 'draft' | 'scheduled' | 'archived';
22
- content: string;
23
- excerpt?: string;
24
- thumbnailUrl?: string;
25
- thumbnailAlt?: string;
26
- tags: string[];
27
- authorId?: string;
28
- readingTimeMinutes?: number;
29
- embeddedMedia: Record<string, EmbeddedMediaEntry>;
30
- seo: SeoMeta;
31
- /** Unix milliseconds. Stored as Firestore Timestamp but always normalized on read. */
32
- publishedAt: number;
33
- /** Unix milliseconds, optional. */
34
- scheduledPublishAt?: number;
35
- /** Unix milliseconds. */
36
- updatedAt: number;
37
- /** Unix milliseconds. */
38
- createdAt: number;
39
- }
@@ -1,27 +0,0 @@
1
- export interface NavItem {
2
- label: string;
3
- url: string;
4
- order?: number;
5
- external?: boolean;
6
- icon?: string;
7
- }
8
- export type SocialPlatform = 'twitter' | 'instagram' | 'github' | 'linkedin' | 'youtube' | 'twitch' | 'bluesky' | 'tiktok' | 'facebook' | 'email' | 'website';
9
- export interface SocialLink {
10
- platform: SocialPlatform;
11
- url: string;
12
- label?: string;
13
- icon?: string;
14
- }
15
- export interface SiteConfig {
16
- id: string;
17
- siteName: string;
18
- siteUrl: string;
19
- description?: string;
20
- logo?: string;
21
- favicon?: string;
22
- nav: NavItem[];
23
- social: SocialLink[];
24
- defaultAuthorId?: string;
25
- /** Unix milliseconds. */
26
- updatedAt: number;
27
- }
@@ -1,5 +0,0 @@
1
- export interface Tag {
2
- id: string;
3
- label: string;
4
- slug: string;
5
- }
@@ -1,13 +0,0 @@
1
- import { User } from 'firebase/auth';
2
- import * as i0 from "@angular/core";
3
- export declare class AuthService {
4
- private readonly auth;
5
- private readonly adminEmail;
6
- readonly user: import("@angular/core").Signal<User | null | undefined>;
7
- readonly isAuthenticated: import("@angular/core").Signal<boolean>;
8
- readonly isAdmin: import("@angular/core").Signal<boolean>;
9
- signInWithGoogle(): Promise<void>;
10
- signOut(): Promise<void>;
11
- static ɵfac: i0.ɵɵFactoryDeclaration<AuthService, never>;
12
- static ɵprov: i0.ɵɵInjectableDeclaration<AuthService>;
13
- }