shared-features 0.0.8 → 0.1.0

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 (91) hide show
  1. package/README.md +205 -2
  2. package/dist/{admin-notifications-D9n9h-eY.cjs → admin-notifications-D1GgYCJW.cjs} +20 -20
  3. package/dist/{admin-notifications-D9n9h-eY.cjs.map → admin-notifications-D1GgYCJW.cjs.map} +1 -1
  4. package/dist/{admin-notifications-p1dy3zIP.js → admin-notifications-NI7I76uY.js} +13 -13
  5. package/dist/{admin-notifications-p1dy3zIP.js.map → admin-notifications-NI7I76uY.js.map} +1 -1
  6. package/dist/{broadcasts-3_WfQMNL.cjs → broadcasts-BMoTZIuX.cjs} +10 -10
  7. package/dist/{broadcasts-3_WfQMNL.cjs.map → broadcasts-BMoTZIuX.cjs.map} +1 -1
  8. package/dist/{broadcasts-DgZUzqMf.js → broadcasts-DnzZkCoy.js} +12 -12
  9. package/dist/{broadcasts-DgZUzqMf.js.map → broadcasts-DnzZkCoy.js.map} +1 -1
  10. package/dist/commonFeatures-Bdt0UZox.js +1255 -0
  11. package/dist/commonFeatures-Bdt0UZox.js.map +1 -0
  12. package/dist/commonFeatures-CiqxxOin.cjs +1276 -0
  13. package/dist/commonFeatures-CiqxxOin.cjs.map +1 -0
  14. package/dist/commonFeatures-Cr5g1E4M.cjs +200 -0
  15. package/dist/commonFeatures-Cr5g1E4M.cjs.map +1 -0
  16. package/dist/commonFeatures-HT-UO7HW.js +201 -0
  17. package/dist/commonFeatures-HT-UO7HW.js.map +1 -0
  18. package/dist/components/common/index.d.ts +53 -0
  19. package/dist/components/common/index.d.ts.map +1 -0
  20. package/dist/components/index.cjs +31 -23
  21. package/dist/components/index.cjs.map +1 -1
  22. package/dist/components/index.d.ts +1 -0
  23. package/dist/components/index.d.ts.map +1 -1
  24. package/dist/components/index.js +21 -13
  25. package/dist/firebase/config.d.ts +34 -0
  26. package/dist/firebase/config.d.ts.map +1 -1
  27. package/dist/hooks/index.cjs +26 -13
  28. package/dist/hooks/index.cjs.map +1 -1
  29. package/dist/hooks/index.d.ts +2 -0
  30. package/dist/hooks/index.d.ts.map +1 -1
  31. package/dist/hooks/index.js +24 -11
  32. package/dist/hooks/useCommonFeatures.d.ts +74 -0
  33. package/dist/hooks/useCommonFeatures.d.ts.map +1 -0
  34. package/dist/hooks/useFeatureFlags.d.ts +134 -0
  35. package/dist/hooks/useFeatureFlags.d.ts.map +1 -0
  36. package/dist/{AnnouncementModal-Bqy0pn3V.cjs → index-Dt5YjYnK.cjs} +209 -14
  37. package/dist/index-Dt5YjYnK.cjs.map +1 -0
  38. package/dist/{AnnouncementModal-sxH4K5gy.js → index-Dv34aG2I.js} +212 -17
  39. package/dist/index-Dv34aG2I.js.map +1 -0
  40. package/dist/index.cjs +125 -60
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.ts +10 -5
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +173 -108
  45. package/dist/index.js.map +1 -1
  46. package/dist/notifications/index.js +14 -14
  47. package/dist/services/commonFeatures.d.ts +22 -0
  48. package/dist/services/commonFeatures.d.ts.map +1 -0
  49. package/dist/services/featureFlags.d.ts +71 -0
  50. package/dist/services/featureFlags.d.ts.map +1 -0
  51. package/dist/services/index.cjs +49 -17
  52. package/dist/services/index.cjs.map +1 -1
  53. package/dist/services/index.d.ts +2 -0
  54. package/dist/services/index.d.ts.map +1 -1
  55. package/dist/services/index.js +75 -43
  56. package/dist/services/index.js.map +1 -1
  57. package/dist/types/commonFeatures.d.ts +194 -0
  58. package/dist/types/commonFeatures.d.ts.map +1 -0
  59. package/dist/types/featureFlags.d.ts +203 -0
  60. package/dist/types/featureFlags.d.ts.map +1 -0
  61. package/dist/types/index.cjs +15 -0
  62. package/dist/types/index.cjs.map +1 -1
  63. package/dist/types/index.d.ts +3 -1
  64. package/dist/types/index.d.ts.map +1 -1
  65. package/dist/types/index.js +15 -0
  66. package/dist/types/index.js.map +1 -1
  67. package/dist/useCommonFeatures-CgyDq6LZ.js +489 -0
  68. package/dist/useCommonFeatures-CgyDq6LZ.js.map +1 -0
  69. package/dist/useCommonFeatures-DnDlhmri.cjs +488 -0
  70. package/dist/useCommonFeatures-DnDlhmri.cjs.map +1 -0
  71. package/dist/useFeatureFlags-BRJSyH9M.js +368 -0
  72. package/dist/useFeatureFlags-BRJSyH9M.js.map +1 -0
  73. package/dist/useFeatureFlags-DXqBJ5Mh.cjs +367 -0
  74. package/dist/useFeatureFlags-DXqBJ5Mh.cjs.map +1 -0
  75. package/dist/{useNotificationEvents-D8DVxah1.js → useNotificationEvents-DAmR7FYF.js} +14 -14
  76. package/dist/{useNotificationEvents-D8DVxah1.js.map → useNotificationEvents-DAmR7FYF.js.map} +1 -1
  77. package/package.json +15 -8
  78. package/dist/AnnouncementModal-Bqy0pn3V.cjs.map +0 -1
  79. package/dist/AnnouncementModal-sxH4K5gy.js.map +0 -1
  80. package/dist/analytics-40-S_fHC.js +0 -440
  81. package/dist/analytics-40-S_fHC.js.map +0 -1
  82. package/dist/analytics-lEzOx2vl.cjs +0 -461
  83. package/dist/analytics-lEzOx2vl.cjs.map +0 -1
  84. package/dist/useBroadcasts-DzpCcbC8.js +0 -161
  85. package/dist/useBroadcasts-DzpCcbC8.js.map +0 -1
  86. package/dist/useBroadcasts-FP6ZrcY_.cjs +0 -160
  87. package/dist/useBroadcasts-FP6ZrcY_.cjs.map +0 -1
  88. package/dist/useCampaigns-BOZ9dDsG.cjs +0 -152
  89. package/dist/useCampaigns-BOZ9dDsG.cjs.map +0 -1
  90. package/dist/useCampaigns-D46b9zuf.js +0 -153
  91. package/dist/useCampaigns-D46b9zuf.js.map +0 -1
@@ -0,0 +1,1276 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ const firestore = require("firebase/firestore");
25
+ const app = require("firebase/app");
26
+ const auth = require("firebase/auth");
27
+ const commonFeatures = require("./commonFeatures-Cr5g1E4M.cjs");
28
+ let state = {
29
+ initialized: false,
30
+ config: null,
31
+ deviceId: null
32
+ };
33
+ function getState() {
34
+ return state;
35
+ }
36
+ function setState(newState) {
37
+ state = { ...state, ...newState };
38
+ }
39
+ function getConfig() {
40
+ if (!state.initialized || !state.config) {
41
+ throw new Error(
42
+ "shared-features has not been initialized. Call initSharedFeatures() first."
43
+ );
44
+ }
45
+ return state.config;
46
+ }
47
+ function isInitialized() {
48
+ return state.initialized;
49
+ }
50
+ const SHARED_FEATURES_APP_NAME = "shared-features";
51
+ let firebaseApp = null;
52
+ let firestoreDb = null;
53
+ let firebaseAuth = null;
54
+ function generateDeviceId() {
55
+ const timestamp = Date.now();
56
+ const randomPart = Math.random().toString(36).substring(2, 15);
57
+ return `device_${timestamp}_${randomPart}`;
58
+ }
59
+ async function getOrCreateDeviceId() {
60
+ const STORAGE_KEY = "shared_features_device_id";
61
+ try {
62
+ const { Preferences } = await import("@capacitor/preferences");
63
+ const result = await Preferences.get({ key: STORAGE_KEY });
64
+ if (result.value) {
65
+ return result.value;
66
+ }
67
+ const newId = generateDeviceId();
68
+ await Preferences.set({ key: STORAGE_KEY, value: newId });
69
+ return newId;
70
+ } catch {
71
+ try {
72
+ const stored = localStorage.getItem(STORAGE_KEY);
73
+ if (stored) {
74
+ return stored;
75
+ }
76
+ const newId = generateDeviceId();
77
+ localStorage.setItem(STORAGE_KEY, newId);
78
+ return newId;
79
+ } catch {
80
+ return generateDeviceId();
81
+ }
82
+ }
83
+ }
84
+ async function initSharedFeatures(config) {
85
+ if (isInitialized() && firebaseApp && firestoreDb && firebaseAuth) {
86
+ const currentConfig = getState().config;
87
+ if (currentConfig && currentConfig.firebaseConfig.projectId === config.firebaseConfig.projectId) {
88
+ return { app: firebaseApp, db: firestoreDb, auth: firebaseAuth };
89
+ }
90
+ }
91
+ const existingApps = app.getApps();
92
+ const existingApp = existingApps.find(
93
+ (app2) => app2.name === SHARED_FEATURES_APP_NAME
94
+ );
95
+ if (existingApp) {
96
+ firebaseApp = existingApp;
97
+ } else {
98
+ firebaseApp = app.initializeApp(config.firebaseConfig, SHARED_FEATURES_APP_NAME);
99
+ }
100
+ firestoreDb = firestore.getFirestore(firebaseApp);
101
+ firebaseAuth = auth.getAuth(firebaseApp);
102
+ const deviceId = await getOrCreateDeviceId();
103
+ setState({
104
+ initialized: true,
105
+ config,
106
+ deviceId
107
+ });
108
+ if (config.debug) {
109
+ console.log("[shared-features] Initialized:", {
110
+ projectId: config.projectId,
111
+ projectName: config.projectName,
112
+ platform: config.platform,
113
+ deviceId
114
+ });
115
+ }
116
+ return { app: firebaseApp, db: firestoreDb, auth: firebaseAuth };
117
+ }
118
+ function getSharedFeaturesApp() {
119
+ if (!firebaseApp) {
120
+ throw new Error(
121
+ "shared-features has not been initialized. Call initSharedFeatures() first."
122
+ );
123
+ }
124
+ return firebaseApp;
125
+ }
126
+ function getSharedFeaturesDb() {
127
+ if (!firestoreDb) {
128
+ throw new Error(
129
+ "shared-features has not been initialized. Call initSharedFeatures() first."
130
+ );
131
+ }
132
+ return firestoreDb;
133
+ }
134
+ function getSharedFeaturesAuth() {
135
+ if (!firebaseAuth) {
136
+ throw new Error(
137
+ "shared-features has not been initialized. Call initSharedFeatures() first."
138
+ );
139
+ }
140
+ return firebaseAuth;
141
+ }
142
+ function getDeviceId() {
143
+ return getState().deviceId;
144
+ }
145
+ const COLLECTION_CAMPAIGNS = "zaions_campaigns";
146
+ const COLLECTION_PRODUCTS = "zaions_products";
147
+ let campaignsCache = null;
148
+ const CACHE_TTL_MS$2 = 5 * 60 * 1e3;
149
+ let productsCache = null;
150
+ function isCacheValid$2() {
151
+ if (!campaignsCache) return false;
152
+ return Date.now() - campaignsCache.timestamp < CACHE_TTL_MS$2;
153
+ }
154
+ function docToCampaign(docId, data) {
155
+ return {
156
+ id: docId,
157
+ productId: data.productId,
158
+ name: data.name,
159
+ status: data.status,
160
+ targetPlatforms: data.targetPlatforms,
161
+ targetAudience: data.targetAudience,
162
+ targetProjects: data.targetProjects || [],
163
+ excludeProductUsers: data.excludeProductUsers,
164
+ placements: data.placements,
165
+ priority: data.priority,
166
+ frequencyDays: data.frequencyDays,
167
+ maxImpressions: data.maxImpressions,
168
+ startDate: data.startDate,
169
+ endDate: data.endDate,
170
+ variant: data.variant,
171
+ customTitle: data.customTitle,
172
+ customTagline: data.customTagline,
173
+ customCta: data.customCta,
174
+ customCtaUrl: data.customCtaUrl,
175
+ customDescription: data.customDescription,
176
+ customProductColor: data.customProductColor,
177
+ customIcon: data.customIcon,
178
+ customFeatures: data.customFeatures,
179
+ totalImpressions: data.totalImpressions,
180
+ totalClicks: data.totalClicks,
181
+ totalCloses: data.totalCloses,
182
+ createdAt: data.createdAt,
183
+ updatedAt: data.updatedAt,
184
+ createdBy: data.createdBy,
185
+ updatedBy: data.updatedBy
186
+ };
187
+ }
188
+ function docToProduct(docId, data) {
189
+ return {
190
+ id: docId,
191
+ name: data.name,
192
+ tagline: data.tagline,
193
+ description: data.description,
194
+ type: data.type,
195
+ url: data.url,
196
+ color: data.color,
197
+ features: data.features || [],
198
+ icon64: data.icon64,
199
+ icon128: data.icon128,
200
+ chromeStoreUrl: data.chromeStoreUrl,
201
+ playStoreUrl: data.playStoreUrl,
202
+ appStoreUrl: data.appStoreUrl,
203
+ webUrl: data.webUrl,
204
+ enabled: data.enabled,
205
+ createdAt: data.createdAt,
206
+ updatedAt: data.updatedAt
207
+ };
208
+ }
209
+ async function fetchProducts() {
210
+ const db = getSharedFeaturesDb();
211
+ const snapshot = await firestore.getDocs(firestore.collection(db, COLLECTION_PRODUCTS));
212
+ const products = snapshot.docs.map((d) => docToProduct(d.id, d.data()));
213
+ productsCache = new Map(products.map((p) => [p.id, p]));
214
+ return products;
215
+ }
216
+ async function getProductById(productId) {
217
+ if (productsCache?.has(productId)) {
218
+ return productsCache.get(productId) || null;
219
+ }
220
+ const db = getSharedFeaturesDb();
221
+ const docSnap = await firestore.getDoc(firestore.doc(db, COLLECTION_PRODUCTS, productId));
222
+ if (!docSnap.exists()) return null;
223
+ const product = docToProduct(docSnap.id, docSnap.data());
224
+ if (!productsCache) productsCache = /* @__PURE__ */ new Map();
225
+ productsCache.set(productId, product);
226
+ return product;
227
+ }
228
+ async function fetchCampaigns(options = {}) {
229
+ const config = getConfig();
230
+ const db = getSharedFeaturesDb();
231
+ if (!options.placement && !options.status && !options.productId && isCacheValid$2()) {
232
+ return campaignsCache.data;
233
+ }
234
+ let q = firestore.query(firestore.collection(db, COLLECTION_CAMPAIGNS));
235
+ if (options.status) {
236
+ q = firestore.query(q, firestore.where("status", "==", options.status));
237
+ }
238
+ if (options.productId) {
239
+ q = firestore.query(q, firestore.where("productId", "==", options.productId));
240
+ }
241
+ q = firestore.query(q, firestore.orderBy("priority", "desc"));
242
+ if (options.limit) {
243
+ q = firestore.query(q, firestore.limit(options.limit));
244
+ }
245
+ const snapshot = await firestore.getDocs(q);
246
+ let campaigns = snapshot.docs.map((d) => docToCampaign(d.id, d.data()));
247
+ if (options.placement) {
248
+ campaigns = campaigns.filter(
249
+ (c) => c.placements.includes(options.placement)
250
+ );
251
+ }
252
+ campaigns = campaigns.filter(
253
+ (c) => c.targetPlatforms.includes(config.platform) || c.targetPlatforms.length === 0
254
+ );
255
+ campaigns = campaigns.filter(
256
+ (c) => c.targetProjects.length === 0 || c.targetProjects.includes(config.projectId)
257
+ );
258
+ if (!options.placement && !options.status && !options.productId) {
259
+ campaignsCache = {
260
+ data: campaigns,
261
+ timestamp: Date.now()
262
+ };
263
+ }
264
+ return campaigns;
265
+ }
266
+ async function fetchActiveCampaigns(placement) {
267
+ const now = firestore.Timestamp.now();
268
+ const campaigns = await fetchCampaigns({ status: "active" });
269
+ if (!productsCache || productsCache.size === 0) {
270
+ await fetchProducts();
271
+ }
272
+ const eligible = campaigns.filter((c) => {
273
+ if (!c.placements.includes(placement)) return false;
274
+ if (c.startDate.toMillis() > now.toMillis()) return false;
275
+ if (c.endDate && c.endDate.toMillis() < now.toMillis()) return false;
276
+ if (c.maxImpressions !== null && c.totalImpressions >= c.maxImpressions)
277
+ return false;
278
+ return true;
279
+ });
280
+ const result = [];
281
+ for (const campaign of eligible) {
282
+ const product = await getProductById(campaign.productId);
283
+ if (product && product.enabled) {
284
+ result.push({ ...campaign, product });
285
+ }
286
+ }
287
+ return result;
288
+ }
289
+ async function getCampaignById(campaignId) {
290
+ const db = getSharedFeaturesDb();
291
+ const docSnap = await firestore.getDoc(firestore.doc(db, COLLECTION_CAMPAIGNS, campaignId));
292
+ if (!docSnap.exists()) return null;
293
+ return docToCampaign(docSnap.id, docSnap.data());
294
+ }
295
+ function clearCampaignsCache() {
296
+ campaignsCache = null;
297
+ }
298
+ function clearProductsCache() {
299
+ productsCache = null;
300
+ }
301
+ const COLLECTION_IMPRESSIONS = "zaions_impressions";
302
+ const LOCAL_STORAGE_KEY = "shared_features_ad_history";
303
+ async function getLocalAdHistory() {
304
+ try {
305
+ const { Preferences } = await import("@capacitor/preferences");
306
+ const result = await Preferences.get({ key: LOCAL_STORAGE_KEY });
307
+ if (result.value) {
308
+ return JSON.parse(result.value);
309
+ }
310
+ } catch {
311
+ try {
312
+ const stored = localStorage.getItem(LOCAL_STORAGE_KEY);
313
+ if (stored) {
314
+ return JSON.parse(stored);
315
+ }
316
+ } catch {
317
+ }
318
+ }
319
+ return {};
320
+ }
321
+ async function saveLocalAdHistory(history) {
322
+ const serialized = JSON.stringify(history);
323
+ try {
324
+ const { Preferences } = await import("@capacitor/preferences");
325
+ await Preferences.set({ key: LOCAL_STORAGE_KEY, value: serialized });
326
+ } catch {
327
+ try {
328
+ localStorage.setItem(LOCAL_STORAGE_KEY, serialized);
329
+ } catch {
330
+ }
331
+ }
332
+ }
333
+ async function updateLocalHistory(campaignId, productId, action, frequencyDays) {
334
+ const history = await getLocalAdHistory();
335
+ const now = Date.now();
336
+ const nextEligibleAt = now + frequencyDays * 24 * 60 * 60 * 1e3;
337
+ const existing = history[campaignId];
338
+ if (existing) {
339
+ history[campaignId] = {
340
+ ...existing,
341
+ lastSeenAt: now,
342
+ impressionCount: action === "impression" ? existing.impressionCount + 1 : existing.impressionCount,
343
+ clicked: existing.clicked || action === "click",
344
+ closed: existing.closed || action === "close",
345
+ nextEligibleAt: action === "impression" ? nextEligibleAt : existing.nextEligibleAt
346
+ };
347
+ } else {
348
+ history[campaignId] = {
349
+ campaignId,
350
+ productId,
351
+ lastSeenAt: now,
352
+ impressionCount: action === "impression" ? 1 : 0,
353
+ clicked: action === "click",
354
+ closed: action === "close",
355
+ nextEligibleAt
356
+ };
357
+ }
358
+ await saveLocalAdHistory(history);
359
+ }
360
+ async function isEligibleForCampaign(campaignId, _frequencyDays = 20) {
361
+ const history = await getLocalAdHistory();
362
+ const entry = history[campaignId];
363
+ if (!entry) return true;
364
+ return Date.now() >= entry.nextEligibleAt;
365
+ }
366
+ async function getEligibleCampaignIds() {
367
+ const history = await getLocalAdHistory();
368
+ const now = Date.now();
369
+ return Object.entries(history).filter(([, entry]) => now >= entry.nextEligibleAt).map(([campaignId]) => campaignId);
370
+ }
371
+ async function getCampaignHistory(campaignId) {
372
+ const history = await getLocalAdHistory();
373
+ return history[campaignId] || null;
374
+ }
375
+ async function recordImpression(input, frequencyDays = 20) {
376
+ const config = getConfig();
377
+ const state2 = getState();
378
+ const db = getSharedFeaturesDb();
379
+ const impressionData = {
380
+ campaignId: input.campaignId,
381
+ productId: input.productId,
382
+ projectId: config.projectId,
383
+ userId: null,
384
+ // Consumer projects don't authenticate with aoneahsan.com
385
+ deviceId: state2.deviceId || "unknown",
386
+ platform: config.platform,
387
+ placement: input.placement,
388
+ action: input.action,
389
+ variant: input.variant,
390
+ timestamp: firestore.serverTimestamp(),
391
+ ...input.sessionId && { sessionId: input.sessionId }
392
+ };
393
+ try {
394
+ await firestore.addDoc(firestore.collection(db, COLLECTION_IMPRESSIONS), impressionData);
395
+ if (config.debug) {
396
+ console.log("[shared-features] Recorded impression:", impressionData);
397
+ }
398
+ } catch (error) {
399
+ if (config.debug) {
400
+ console.error("[shared-features] Failed to record impression:", error);
401
+ }
402
+ }
403
+ await updateLocalHistory(
404
+ input.campaignId,
405
+ input.productId,
406
+ input.action,
407
+ frequencyDays
408
+ );
409
+ }
410
+ async function trackImpression(campaignId, productId, placement, variant, frequencyDays) {
411
+ await recordImpression(
412
+ {
413
+ campaignId,
414
+ productId,
415
+ placement,
416
+ action: "impression",
417
+ variant
418
+ },
419
+ frequencyDays
420
+ );
421
+ }
422
+ async function trackClick(campaignId, productId, placement, variant) {
423
+ await recordImpression({
424
+ campaignId,
425
+ productId,
426
+ placement,
427
+ action: "click",
428
+ variant
429
+ });
430
+ }
431
+ async function trackClose(campaignId, productId, placement, variant) {
432
+ await recordImpression({
433
+ campaignId,
434
+ productId,
435
+ placement,
436
+ action: "close",
437
+ variant
438
+ });
439
+ }
440
+ let flagsCache = null;
441
+ const CACHE_TTL_MS$1 = 2 * 60 * 1e3;
442
+ function isCacheValid$1() {
443
+ if (!flagsCache || !flagsCache.data) return false;
444
+ return Date.now() - flagsCache.timestamp < CACHE_TTL_MS$1;
445
+ }
446
+ function clearFeatureFlagsCache() {
447
+ flagsCache = null;
448
+ }
449
+ function docToFeatureFlags(docId, data) {
450
+ return {
451
+ id: docId,
452
+ globalEnabled: data.globalEnabled ?? true,
453
+ currentApiVersion: data.currentApiVersion ?? "v1",
454
+ supportedApiVersions: data.supportedApiVersions ?? ["v1"],
455
+ features: data.features,
456
+ maintenanceMode: data.maintenanceMode ?? false,
457
+ maintenanceMessage: data.maintenanceMessage,
458
+ maintenanceEndTime: data.maintenanceEndTime,
459
+ updatedAt: data.updatedAt,
460
+ updatedBy: data.updatedBy
461
+ };
462
+ }
463
+ function getConsumerVersion(featureId, consumerVersions) {
464
+ if (!consumerVersions) return void 0;
465
+ return consumerVersions[featureId];
466
+ }
467
+ async function fetchFeatureFlags(forceRefresh = false) {
468
+ if (!forceRefresh && isCacheValid$1()) {
469
+ return flagsCache.data;
470
+ }
471
+ try {
472
+ const db = getSharedFeaturesDb();
473
+ const docRef = firestore.doc(db, commonFeatures.COLLECTION_FEATURE_FLAGS, commonFeatures.FEATURE_FLAGS_DOC_ID);
474
+ const docSnap = await firestore.getDoc(docRef);
475
+ if (!docSnap.exists()) {
476
+ const config2 = getConfig();
477
+ if (config2.debug) {
478
+ console.log(
479
+ "[shared-features] Feature flags document not found, using defaults"
480
+ );
481
+ }
482
+ const defaultDoc = {
483
+ ...commonFeatures.DEFAULT_FEATURE_FLAGS,
484
+ updatedAt: firestore.Timestamp.now(),
485
+ updatedBy: "system"
486
+ };
487
+ flagsCache = {
488
+ data: defaultDoc,
489
+ timestamp: Date.now()
490
+ };
491
+ return defaultDoc;
492
+ }
493
+ const flags = docToFeatureFlags(docSnap.id, docSnap.data());
494
+ flagsCache = {
495
+ data: flags,
496
+ timestamp: Date.now()
497
+ };
498
+ const config = getConfig();
499
+ if (config.debug) {
500
+ console.log("[shared-features] Feature flags fetched:", {
501
+ globalEnabled: flags.globalEnabled,
502
+ maintenanceMode: flags.maintenanceMode,
503
+ apiVersion: flags.currentApiVersion
504
+ });
505
+ }
506
+ return flags;
507
+ } catch (error) {
508
+ const config = getConfig();
509
+ if (config.debug) {
510
+ console.error("[shared-features] Error fetching feature flags:", error);
511
+ }
512
+ if (flagsCache?.data) {
513
+ return flagsCache.data;
514
+ }
515
+ return null;
516
+ }
517
+ }
518
+ function subscribeToFeatureFlags(callback) {
519
+ const db = getSharedFeaturesDb();
520
+ const docRef = firestore.doc(db, commonFeatures.COLLECTION_FEATURE_FLAGS, commonFeatures.FEATURE_FLAGS_DOC_ID);
521
+ return firestore.onSnapshot(
522
+ docRef,
523
+ (docSnap) => {
524
+ if (!docSnap.exists()) {
525
+ callback(null);
526
+ return;
527
+ }
528
+ const flags = docToFeatureFlags(docSnap.id, docSnap.data());
529
+ flagsCache = {
530
+ data: flags,
531
+ timestamp: Date.now()
532
+ };
533
+ callback(flags);
534
+ },
535
+ (error) => {
536
+ const config = getConfig();
537
+ if (config.debug) {
538
+ console.error(
539
+ "[shared-features] Error subscribing to feature flags:",
540
+ error
541
+ );
542
+ }
543
+ callback(null);
544
+ }
545
+ );
546
+ }
547
+ async function checkFeatureAvailability(featureId, consumerVersions) {
548
+ const flags = await fetchFeatureFlags();
549
+ const config = getConfig();
550
+ const unavailable = {
551
+ available: false,
552
+ enabled: false,
553
+ version: 1,
554
+ deprecated: false,
555
+ upgradeRequired: false,
556
+ unavailableReason: "Feature flags not loaded"
557
+ };
558
+ if (!flags) {
559
+ return unavailable;
560
+ }
561
+ if (!flags.globalEnabled) {
562
+ return {
563
+ ...unavailable,
564
+ unavailableReason: "shared-features is globally disabled"
565
+ };
566
+ }
567
+ if (flags.maintenanceMode) {
568
+ return {
569
+ ...unavailable,
570
+ unavailableReason: flags.maintenanceMessage || "Maintenance in progress"
571
+ };
572
+ }
573
+ const featureConfig = flags.features[featureId];
574
+ if (!featureConfig) {
575
+ return {
576
+ ...unavailable,
577
+ unavailableReason: `Feature '${featureId}' not found in configuration`
578
+ };
579
+ }
580
+ if (!featureConfig.enabled) {
581
+ return {
582
+ ...unavailable,
583
+ version: featureConfig.version,
584
+ unavailableReason: `Feature '${featureId}' is not enabled`
585
+ };
586
+ }
587
+ if (featureConfig.availablePlatforms && featureConfig.availablePlatforms.length > 0) {
588
+ if (!featureConfig.availablePlatforms.includes(config.platform)) {
589
+ return {
590
+ ...unavailable,
591
+ version: featureConfig.version,
592
+ unavailableReason: `Feature '${featureId}' is not available on platform '${config.platform}'`
593
+ };
594
+ }
595
+ }
596
+ if (featureConfig.availableProjects && featureConfig.availableProjects.length > 0) {
597
+ if (!featureConfig.availableProjects.includes(config.projectId)) {
598
+ return {
599
+ ...unavailable,
600
+ version: featureConfig.version,
601
+ unavailableReason: `Feature '${featureId}' is not available for project '${config.projectId}'`
602
+ };
603
+ }
604
+ }
605
+ const consumerVersion = getConsumerVersion(featureId, consumerVersions);
606
+ const currentVersion = featureConfig.version;
607
+ const minVersion = featureConfig.minVersion;
608
+ const maxVersion = featureConfig.maxVersion;
609
+ let deprecated = false;
610
+ let deprecationWarning;
611
+ let upgradeRequired = false;
612
+ let upgradeMessage;
613
+ if (consumerVersion !== void 0) {
614
+ if (consumerVersion < minVersion) {
615
+ upgradeRequired = true;
616
+ upgradeMessage = `Feature '${featureId}' requires minimum version ${minVersion}, but consumer is using version ${consumerVersion}. Please upgrade.`;
617
+ } else if (consumerVersion < currentVersion) {
618
+ deprecated = true;
619
+ deprecationWarning = featureConfig.deprecationMessage || `Feature '${featureId}' version ${consumerVersion} is deprecated. Current version is ${currentVersion}.`;
620
+ } else if (consumerVersion > maxVersion) {
621
+ return {
622
+ ...unavailable,
623
+ version: currentVersion,
624
+ unavailableReason: `Feature '${featureId}' version ${consumerVersion} is not yet supported. Maximum supported version is ${maxVersion}.`
625
+ };
626
+ }
627
+ }
628
+ return {
629
+ available: !upgradeRequired,
630
+ enabled: true,
631
+ version: currentVersion,
632
+ deprecated,
633
+ deprecationWarning,
634
+ upgradeRequired,
635
+ upgradeMessage
636
+ };
637
+ }
638
+ function isFeatureEnabled(featureId) {
639
+ if (!flagsCache?.data) return false;
640
+ const flags = flagsCache.data;
641
+ if (!flags.globalEnabled || flags.maintenanceMode) return false;
642
+ const featureConfig = flags.features[featureId];
643
+ if (!featureConfig || !featureConfig.enabled) return false;
644
+ const config = getConfig();
645
+ if (featureConfig.availablePlatforms && featureConfig.availablePlatforms.length > 0) {
646
+ if (!featureConfig.availablePlatforms.includes(config.platform)) {
647
+ return false;
648
+ }
649
+ }
650
+ if (featureConfig.availableProjects && featureConfig.availableProjects.length > 0) {
651
+ if (!featureConfig.availableProjects.includes(config.projectId)) {
652
+ return false;
653
+ }
654
+ }
655
+ return true;
656
+ }
657
+ function getFeatureVersion(featureId) {
658
+ if (!flagsCache?.data) return 0;
659
+ return flagsCache.data.features[featureId]?.version ?? 0;
660
+ }
661
+ async function getSharedFeaturesStatus(consumerVersions) {
662
+ const flags = await fetchFeatureFlags();
663
+ const defaultStatus = {
664
+ operational: false,
665
+ maintenanceMode: false,
666
+ apiVersion: "v1",
667
+ features: {},
668
+ deprecatedFeatures: [],
669
+ upgradeRequiredFeatures: [],
670
+ fetchedAt: /* @__PURE__ */ new Date()
671
+ };
672
+ if (!flags) {
673
+ return defaultStatus;
674
+ }
675
+ const featureIds = [
676
+ "campaigns",
677
+ "broadcasts",
678
+ "contactInfo",
679
+ "developerInfo",
680
+ "socialLinks",
681
+ "paymentOptions",
682
+ "addressInfo",
683
+ "services",
684
+ "skills",
685
+ "testimonials",
686
+ "projects"
687
+ ];
688
+ const features = {};
689
+ const deprecatedFeatures = [];
690
+ const upgradeRequiredFeatures = [];
691
+ for (const featureId of featureIds) {
692
+ const availability = await checkFeatureAvailability(
693
+ featureId,
694
+ consumerVersions
695
+ );
696
+ features[featureId] = availability;
697
+ if (availability.deprecated) {
698
+ deprecatedFeatures.push(featureId);
699
+ }
700
+ if (availability.upgradeRequired) {
701
+ upgradeRequiredFeatures.push(featureId);
702
+ }
703
+ }
704
+ return {
705
+ operational: flags.globalEnabled && !flags.maintenanceMode,
706
+ maintenanceMode: flags.maintenanceMode,
707
+ maintenanceMessage: flags.maintenanceMessage,
708
+ apiVersion: flags.currentApiVersion,
709
+ features,
710
+ deprecatedFeatures,
711
+ upgradeRequiredFeatures,
712
+ fetchedAt: /* @__PURE__ */ new Date()
713
+ };
714
+ }
715
+ async function updateFeatureConfig(input, adminEmail) {
716
+ const db = getSharedFeaturesDb();
717
+ const docRef = firestore.doc(db, commonFeatures.COLLECTION_FEATURE_FLAGS, commonFeatures.FEATURE_FLAGS_DOC_ID);
718
+ const docSnap = await firestore.getDoc(docRef);
719
+ let currentFlags;
720
+ if (!docSnap.exists()) {
721
+ currentFlags = {
722
+ ...commonFeatures.DEFAULT_FEATURE_FLAGS,
723
+ updatedAt: firestore.Timestamp.now(),
724
+ updatedBy: adminEmail
725
+ };
726
+ } else {
727
+ currentFlags = docToFeatureFlags(docSnap.id, docSnap.data());
728
+ }
729
+ const featureConfig = currentFlags.features[input.featureId];
730
+ const updatedFeature = {
731
+ enabled: input.enabled ?? featureConfig.enabled,
732
+ version: input.version ?? featureConfig.version,
733
+ minVersion: input.minVersion ?? featureConfig.minVersion,
734
+ maxVersion: input.maxVersion ?? featureConfig.maxVersion,
735
+ deprecationMessage: input.deprecationMessage ?? featureConfig.deprecationMessage,
736
+ requiresAuth: input.requiresAuth ?? featureConfig.requiresAuth,
737
+ availablePlatforms: input.availablePlatforms ?? featureConfig.availablePlatforms,
738
+ availableProjects: input.availableProjects ?? featureConfig.availableProjects
739
+ };
740
+ await firestore.setDoc(
741
+ docRef,
742
+ {
743
+ ...currentFlags,
744
+ features: {
745
+ ...currentFlags.features,
746
+ [input.featureId]: updatedFeature
747
+ },
748
+ updatedAt: firestore.Timestamp.now(),
749
+ updatedBy: adminEmail
750
+ },
751
+ { merge: true }
752
+ );
753
+ clearFeatureFlagsCache();
754
+ }
755
+ async function updateGlobalFlags(input, adminEmail) {
756
+ const db = getSharedFeaturesDb();
757
+ const docRef = firestore.doc(db, commonFeatures.COLLECTION_FEATURE_FLAGS, commonFeatures.FEATURE_FLAGS_DOC_ID);
758
+ const updateData = {
759
+ updatedAt: firestore.Timestamp.now(),
760
+ updatedBy: adminEmail
761
+ };
762
+ if (input.globalEnabled !== void 0) {
763
+ updateData.globalEnabled = input.globalEnabled;
764
+ }
765
+ if (input.currentApiVersion !== void 0) {
766
+ updateData.currentApiVersion = input.currentApiVersion;
767
+ }
768
+ if (input.supportedApiVersions !== void 0) {
769
+ updateData.supportedApiVersions = input.supportedApiVersions;
770
+ }
771
+ if (input.maintenanceMode !== void 0) {
772
+ updateData.maintenanceMode = input.maintenanceMode;
773
+ }
774
+ if (input.maintenanceMessage !== void 0) {
775
+ updateData.maintenanceMessage = input.maintenanceMessage;
776
+ }
777
+ if (input.maintenanceEndTime !== void 0) {
778
+ updateData.maintenanceEndTime = input.maintenanceEndTime ? firestore.Timestamp.fromDate(input.maintenanceEndTime) : null;
779
+ }
780
+ await firestore.setDoc(docRef, updateData, { merge: true });
781
+ clearFeatureFlagsCache();
782
+ }
783
+ async function initializeFeatureFlags(adminEmail) {
784
+ const db = getSharedFeaturesDb();
785
+ const docRef = firestore.doc(db, commonFeatures.COLLECTION_FEATURE_FLAGS, commonFeatures.FEATURE_FLAGS_DOC_ID);
786
+ const docSnap = await firestore.getDoc(docRef);
787
+ if (docSnap.exists()) {
788
+ throw new Error("Feature flags document already exists");
789
+ }
790
+ await firestore.setDoc(docRef, {
791
+ ...commonFeatures.DEFAULT_FEATURE_FLAGS,
792
+ updatedAt: firestore.Timestamp.now(),
793
+ updatedBy: adminEmail
794
+ });
795
+ clearFeatureFlagsCache();
796
+ }
797
+ const CACHE_TTL_MS = 5 * 60 * 1e3;
798
+ let contactInfoCache = null;
799
+ let developerInfoCache = null;
800
+ let addressInfoCache = null;
801
+ let socialLinksCache = null;
802
+ let paymentOptionsCache = null;
803
+ let servicesCache = null;
804
+ let skillsCache = null;
805
+ let testimonialsCache = null;
806
+ function isCacheValid(cache) {
807
+ if (!cache || !cache.data) return false;
808
+ return Date.now() - cache.timestamp < CACHE_TTL_MS;
809
+ }
810
+ function clearAllCommonFeaturesCache() {
811
+ contactInfoCache = null;
812
+ developerInfoCache = null;
813
+ addressInfoCache = null;
814
+ socialLinksCache = null;
815
+ paymentOptionsCache = null;
816
+ servicesCache = null;
817
+ skillsCache = null;
818
+ testimonialsCache = null;
819
+ }
820
+ function docToContactInfo(docId, data) {
821
+ return {
822
+ id: docId,
823
+ email: data.email || "",
824
+ supportEmail: data.supportEmail,
825
+ phone: data.phone,
826
+ whatsapp: data.whatsapp,
827
+ telegram: data.telegram,
828
+ skype: data.skype,
829
+ freelanceAvailable: data.freelanceAvailable ?? false,
830
+ workingHours: data.workingHours,
831
+ timezone: data.timezone,
832
+ preferredContact: data.preferredContact,
833
+ responseTime: data.responseTime,
834
+ updatedAt: data.updatedAt
835
+ };
836
+ }
837
+ async function fetchContactInfo() {
838
+ if (!isFeatureEnabled("contactInfo")) {
839
+ const config = getConfig();
840
+ if (config.debug) console.log("[shared-features] contactInfo feature is disabled");
841
+ return null;
842
+ }
843
+ if (isCacheValid(contactInfoCache)) return contactInfoCache.data;
844
+ try {
845
+ const db = getSharedFeaturesDb();
846
+ const docRef = firestore.doc(db, commonFeatures.COMMON_FEATURE_COLLECTIONS.CONTACT_INFO, "main");
847
+ const docSnap = await firestore.getDoc(docRef);
848
+ if (!docSnap.exists()) return null;
849
+ const data = docToContactInfo(docSnap.id, docSnap.data());
850
+ contactInfoCache = { data, timestamp: Date.now() };
851
+ return data;
852
+ } catch (error) {
853
+ const config = getConfig();
854
+ if (config.debug) console.error("[shared-features] Error fetching contact info:", error);
855
+ return contactInfoCache?.data ?? null;
856
+ }
857
+ }
858
+ function subscribeToContactInfo(callback) {
859
+ const db = getSharedFeaturesDb();
860
+ const docRef = firestore.doc(db, commonFeatures.COMMON_FEATURE_COLLECTIONS.CONTACT_INFO, "main");
861
+ return firestore.onSnapshot(docRef, (docSnap) => {
862
+ if (!docSnap.exists()) {
863
+ callback(null);
864
+ return;
865
+ }
866
+ const data = docToContactInfo(docSnap.id, docSnap.data());
867
+ contactInfoCache = { data, timestamp: Date.now() };
868
+ callback(data);
869
+ });
870
+ }
871
+ function clearContactInfoCache() {
872
+ contactInfoCache = null;
873
+ }
874
+ function docToDeveloperInfo(docId, data) {
875
+ return {
876
+ id: docId,
877
+ name: data.name || "",
878
+ title: data.title || "",
879
+ tagline: data.tagline,
880
+ bio: data.bio || "",
881
+ shortBio: data.shortBio,
882
+ avatar: data.avatar,
883
+ website: data.website,
884
+ github: data.github,
885
+ linkedin: data.linkedin,
886
+ twitter: data.twitter,
887
+ yearsOfExperience: data.yearsOfExperience,
888
+ location: data.location,
889
+ availableForHire: data.availableForHire ?? false,
890
+ resumeUrl: data.resumeUrl,
891
+ updatedAt: data.updatedAt
892
+ };
893
+ }
894
+ async function fetchDeveloperInfo() {
895
+ if (!isFeatureEnabled("developerInfo")) {
896
+ const config = getConfig();
897
+ if (config.debug) console.log("[shared-features] developerInfo feature is disabled");
898
+ return null;
899
+ }
900
+ if (isCacheValid(developerInfoCache)) return developerInfoCache.data;
901
+ try {
902
+ const db = getSharedFeaturesDb();
903
+ const docRef = firestore.doc(db, commonFeatures.COMMON_FEATURE_COLLECTIONS.DEVELOPER_INFO, "main");
904
+ const docSnap = await firestore.getDoc(docRef);
905
+ if (!docSnap.exists()) return null;
906
+ const data = docToDeveloperInfo(docSnap.id, docSnap.data());
907
+ developerInfoCache = { data, timestamp: Date.now() };
908
+ return data;
909
+ } catch (error) {
910
+ const config = getConfig();
911
+ if (config.debug) console.error("[shared-features] Error fetching developer info:", error);
912
+ return developerInfoCache?.data ?? null;
913
+ }
914
+ }
915
+ function subscribeToDeveloperInfo(callback) {
916
+ const db = getSharedFeaturesDb();
917
+ const docRef = firestore.doc(db, commonFeatures.COMMON_FEATURE_COLLECTIONS.DEVELOPER_INFO, "main");
918
+ return firestore.onSnapshot(docRef, (docSnap) => {
919
+ if (!docSnap.exists()) {
920
+ callback(null);
921
+ return;
922
+ }
923
+ const data = docToDeveloperInfo(docSnap.id, docSnap.data());
924
+ developerInfoCache = { data, timestamp: Date.now() };
925
+ callback(data);
926
+ });
927
+ }
928
+ function clearDeveloperInfoCache() {
929
+ developerInfoCache = null;
930
+ }
931
+ function docToAddressInfo(docId, data) {
932
+ return {
933
+ id: docId,
934
+ label: data.label,
935
+ streetAddress: data.streetAddress,
936
+ city: data.city,
937
+ state: data.state,
938
+ postalCode: data.postalCode,
939
+ country: data.country,
940
+ fullAddress: data.fullAddress,
941
+ googleMapsUrl: data.googleMapsUrl,
942
+ isPublic: data.isPublic ?? false,
943
+ updatedAt: data.updatedAt
944
+ };
945
+ }
946
+ async function fetchAddressInfo() {
947
+ if (!isFeatureEnabled("addressInfo")) {
948
+ const config = getConfig();
949
+ if (config.debug) console.log("[shared-features] addressInfo feature is disabled");
950
+ return null;
951
+ }
952
+ if (isCacheValid(addressInfoCache)) return addressInfoCache.data;
953
+ try {
954
+ const db = getSharedFeaturesDb();
955
+ const docRef = firestore.doc(db, commonFeatures.COMMON_FEATURE_COLLECTIONS.ADDRESS_INFO, "main");
956
+ const docSnap = await firestore.getDoc(docRef);
957
+ if (!docSnap.exists()) return null;
958
+ const data = docToAddressInfo(docSnap.id, docSnap.data());
959
+ if (!data.isPublic) return null;
960
+ addressInfoCache = { data, timestamp: Date.now() };
961
+ return data;
962
+ } catch (error) {
963
+ const config = getConfig();
964
+ if (config.debug) console.error("[shared-features] Error fetching address info:", error);
965
+ return addressInfoCache?.data ?? null;
966
+ }
967
+ }
968
+ function clearAddressInfoCache() {
969
+ addressInfoCache = null;
970
+ }
971
+ function docToSocialLink(docId, data) {
972
+ return {
973
+ id: docId,
974
+ platform: data.platform,
975
+ url: data.url || "",
976
+ displayName: data.displayName,
977
+ username: data.username,
978
+ icon: data.icon,
979
+ order: data.order ?? 0,
980
+ isActive: data.isActive ?? true,
981
+ showIn: data.showIn ?? ["footer"],
982
+ updatedAt: data.updatedAt
983
+ };
984
+ }
985
+ async function fetchSocialLinks(options = {}) {
986
+ if (!isFeatureEnabled("socialLinks")) {
987
+ const config = getConfig();
988
+ if (config.debug) console.log("[shared-features] socialLinks feature is disabled");
989
+ return [];
990
+ }
991
+ if (!options.showIn && options.activeOnly !== false && isCacheValid(socialLinksCache)) {
992
+ return socialLinksCache.data ?? [];
993
+ }
994
+ try {
995
+ const db = getSharedFeaturesDb();
996
+ let q = firestore.query(firestore.collection(db, commonFeatures.COMMON_FEATURE_COLLECTIONS.SOCIAL_LINKS), firestore.orderBy("order", "asc"));
997
+ const snapshot = await firestore.getDocs(q);
998
+ let links = snapshot.docs.map((d) => docToSocialLink(d.id, d.data()));
999
+ if (options.activeOnly !== false) {
1000
+ links = links.filter((l) => l.isActive);
1001
+ }
1002
+ if (options.showIn && options.showIn.length > 0) {
1003
+ links = links.filter((l) => options.showIn.some((loc) => l.showIn.includes(loc)));
1004
+ }
1005
+ if (!options.showIn && options.activeOnly !== false) {
1006
+ socialLinksCache = { data: links, timestamp: Date.now() };
1007
+ }
1008
+ return links;
1009
+ } catch (error) {
1010
+ const config = getConfig();
1011
+ if (config.debug) console.error("[shared-features] Error fetching social links:", error);
1012
+ return socialLinksCache?.data ?? [];
1013
+ }
1014
+ }
1015
+ function clearSocialLinksCache() {
1016
+ socialLinksCache = null;
1017
+ }
1018
+ function docToPaymentOption(docId, data) {
1019
+ return {
1020
+ id: docId,
1021
+ type: data.type,
1022
+ name: data.name || "",
1023
+ description: data.description,
1024
+ icon: data.icon,
1025
+ details: data.details || {},
1026
+ isActive: data.isActive ?? true,
1027
+ isPrimary: data.isPrimary ?? false,
1028
+ order: data.order ?? 0,
1029
+ updatedAt: data.updatedAt
1030
+ };
1031
+ }
1032
+ async function fetchPaymentOptions(options = {}) {
1033
+ if (!isFeatureEnabled("paymentOptions")) {
1034
+ const config = getConfig();
1035
+ if (config.debug) console.log("[shared-features] paymentOptions feature is disabled");
1036
+ return [];
1037
+ }
1038
+ if (!options.type && options.activeOnly !== false && isCacheValid(paymentOptionsCache)) {
1039
+ return paymentOptionsCache.data ?? [];
1040
+ }
1041
+ try {
1042
+ const db = getSharedFeaturesDb();
1043
+ let q = firestore.query(firestore.collection(db, commonFeatures.COMMON_FEATURE_COLLECTIONS.PAYMENT_OPTIONS), firestore.orderBy("order", "asc"));
1044
+ const snapshot = await firestore.getDocs(q);
1045
+ let items = snapshot.docs.map((d) => docToPaymentOption(d.id, d.data()));
1046
+ if (options.activeOnly !== false) {
1047
+ items = items.filter((i) => i.isActive);
1048
+ }
1049
+ if (options.type) {
1050
+ items = items.filter((i) => i.type === options.type);
1051
+ }
1052
+ if (!options.type && options.activeOnly !== false) {
1053
+ paymentOptionsCache = { data: items, timestamp: Date.now() };
1054
+ }
1055
+ return items;
1056
+ } catch (error) {
1057
+ const config = getConfig();
1058
+ if (config.debug) console.error("[shared-features] Error fetching payment options:", error);
1059
+ return paymentOptionsCache?.data ?? [];
1060
+ }
1061
+ }
1062
+ function clearPaymentOptionsCache() {
1063
+ paymentOptionsCache = null;
1064
+ }
1065
+ function docToService(docId, data) {
1066
+ return {
1067
+ id: docId,
1068
+ title: data.title || "",
1069
+ description: data.description || "",
1070
+ shortDescription: data.shortDescription,
1071
+ category: data.category,
1072
+ icon: data.icon,
1073
+ features: data.features,
1074
+ technologies: data.technologies,
1075
+ priceRange: data.priceRange,
1076
+ isActive: data.isActive ?? true,
1077
+ isFeatured: data.isFeatured ?? false,
1078
+ order: data.order ?? 0,
1079
+ updatedAt: data.updatedAt
1080
+ };
1081
+ }
1082
+ async function fetchServices(options = {}) {
1083
+ if (!isFeatureEnabled("services")) {
1084
+ const config = getConfig();
1085
+ if (config.debug) console.log("[shared-features] services feature is disabled");
1086
+ return [];
1087
+ }
1088
+ if (!options.category && !options.featuredOnly && options.activeOnly !== false && isCacheValid(servicesCache)) {
1089
+ return servicesCache.data ?? [];
1090
+ }
1091
+ try {
1092
+ const db = getSharedFeaturesDb();
1093
+ let q = firestore.query(firestore.collection(db, commonFeatures.COMMON_FEATURE_COLLECTIONS.SERVICES), firestore.orderBy("order", "asc"));
1094
+ const snapshot = await firestore.getDocs(q);
1095
+ let items = snapshot.docs.map((d) => docToService(d.id, d.data()));
1096
+ if (options.activeOnly !== false) {
1097
+ items = items.filter((i) => i.isActive);
1098
+ }
1099
+ if (options.featuredOnly) {
1100
+ items = items.filter((i) => i.isFeatured);
1101
+ }
1102
+ if (options.category) {
1103
+ items = items.filter((i) => i.category === options.category);
1104
+ }
1105
+ if (!options.category && !options.featuredOnly && options.activeOnly !== false) {
1106
+ servicesCache = { data: items, timestamp: Date.now() };
1107
+ }
1108
+ return items;
1109
+ } catch (error) {
1110
+ const config = getConfig();
1111
+ if (config.debug) console.error("[shared-features] Error fetching services:", error);
1112
+ return servicesCache?.data ?? [];
1113
+ }
1114
+ }
1115
+ function clearServicesCache() {
1116
+ servicesCache = null;
1117
+ }
1118
+ function docToSkill(docId, data) {
1119
+ return {
1120
+ id: docId,
1121
+ name: data.name || "",
1122
+ category: data.category,
1123
+ level: data.level,
1124
+ yearsOfExperience: data.yearsOfExperience,
1125
+ icon: data.icon,
1126
+ color: data.color,
1127
+ isActive: data.isActive ?? true,
1128
+ isFeatured: data.isFeatured ?? false,
1129
+ order: data.order ?? 0,
1130
+ updatedAt: data.updatedAt
1131
+ };
1132
+ }
1133
+ async function fetchSkills(options = {}) {
1134
+ if (!isFeatureEnabled("skills")) {
1135
+ const config = getConfig();
1136
+ if (config.debug) console.log("[shared-features] skills feature is disabled");
1137
+ return [];
1138
+ }
1139
+ if (!options.category && !options.featuredOnly && options.activeOnly !== false && isCacheValid(skillsCache)) {
1140
+ return skillsCache.data ?? [];
1141
+ }
1142
+ try {
1143
+ const db = getSharedFeaturesDb();
1144
+ let q = firestore.query(firestore.collection(db, commonFeatures.COMMON_FEATURE_COLLECTIONS.SKILLS), firestore.orderBy("order", "asc"));
1145
+ const snapshot = await firestore.getDocs(q);
1146
+ let items = snapshot.docs.map((d) => docToSkill(d.id, d.data()));
1147
+ if (options.activeOnly !== false) {
1148
+ items = items.filter((i) => i.isActive);
1149
+ }
1150
+ if (options.featuredOnly) {
1151
+ items = items.filter((i) => i.isFeatured);
1152
+ }
1153
+ if (options.category) {
1154
+ items = items.filter((i) => i.category === options.category);
1155
+ }
1156
+ if (!options.category && !options.featuredOnly && options.activeOnly !== false) {
1157
+ skillsCache = { data: items, timestamp: Date.now() };
1158
+ }
1159
+ return items;
1160
+ } catch (error) {
1161
+ const config = getConfig();
1162
+ if (config.debug) console.error("[shared-features] Error fetching skills:", error);
1163
+ return skillsCache?.data ?? [];
1164
+ }
1165
+ }
1166
+ function clearSkillsCache() {
1167
+ skillsCache = null;
1168
+ }
1169
+ function docToTestimonial(docId, data) {
1170
+ return {
1171
+ id: docId,
1172
+ authorName: data.authorName || "",
1173
+ authorTitle: data.authorTitle,
1174
+ authorCompany: data.authorCompany,
1175
+ authorAvatar: data.authorAvatar,
1176
+ authorLinkedin: data.authorLinkedin,
1177
+ content: data.content || "",
1178
+ shortContent: data.shortContent,
1179
+ rating: data.rating,
1180
+ projectName: data.projectName,
1181
+ projectUrl: data.projectUrl,
1182
+ date: data.date,
1183
+ isActive: data.isActive ?? true,
1184
+ isFeatured: data.isFeatured ?? false,
1185
+ order: data.order ?? 0,
1186
+ updatedAt: data.updatedAt
1187
+ };
1188
+ }
1189
+ async function fetchTestimonials(options = {}) {
1190
+ if (!isFeatureEnabled("testimonials")) {
1191
+ const config = getConfig();
1192
+ if (config.debug) console.log("[shared-features] testimonials feature is disabled");
1193
+ return [];
1194
+ }
1195
+ if (!options.featuredOnly && !options.limit && options.activeOnly !== false && isCacheValid(testimonialsCache)) {
1196
+ return testimonialsCache.data ?? [];
1197
+ }
1198
+ try {
1199
+ const db = getSharedFeaturesDb();
1200
+ let q = firestore.query(firestore.collection(db, commonFeatures.COMMON_FEATURE_COLLECTIONS.TESTIMONIALS), firestore.orderBy("order", "asc"));
1201
+ if (options.limit) {
1202
+ q = firestore.query(q, firestore.limit(options.limit));
1203
+ }
1204
+ const snapshot = await firestore.getDocs(q);
1205
+ let items = snapshot.docs.map((d) => docToTestimonial(d.id, d.data()));
1206
+ if (options.activeOnly !== false) {
1207
+ items = items.filter((i) => i.isActive);
1208
+ }
1209
+ if (options.featuredOnly) {
1210
+ items = items.filter((i) => i.isFeatured);
1211
+ }
1212
+ if (!options.featuredOnly && !options.limit && options.activeOnly !== false) {
1213
+ testimonialsCache = { data: items, timestamp: Date.now() };
1214
+ }
1215
+ return items;
1216
+ } catch (error) {
1217
+ const config = getConfig();
1218
+ if (config.debug) console.error("[shared-features] Error fetching testimonials:", error);
1219
+ return testimonialsCache?.data ?? [];
1220
+ }
1221
+ }
1222
+ function clearTestimonialsCache() {
1223
+ testimonialsCache = null;
1224
+ }
1225
+ exports.checkFeatureAvailability = checkFeatureAvailability;
1226
+ exports.clearAddressInfoCache = clearAddressInfoCache;
1227
+ exports.clearAllCommonFeaturesCache = clearAllCommonFeaturesCache;
1228
+ exports.clearCampaignsCache = clearCampaignsCache;
1229
+ exports.clearContactInfoCache = clearContactInfoCache;
1230
+ exports.clearDeveloperInfoCache = clearDeveloperInfoCache;
1231
+ exports.clearFeatureFlagsCache = clearFeatureFlagsCache;
1232
+ exports.clearPaymentOptionsCache = clearPaymentOptionsCache;
1233
+ exports.clearProductsCache = clearProductsCache;
1234
+ exports.clearServicesCache = clearServicesCache;
1235
+ exports.clearSkillsCache = clearSkillsCache;
1236
+ exports.clearSocialLinksCache = clearSocialLinksCache;
1237
+ exports.clearTestimonialsCache = clearTestimonialsCache;
1238
+ exports.fetchActiveCampaigns = fetchActiveCampaigns;
1239
+ exports.fetchAddressInfo = fetchAddressInfo;
1240
+ exports.fetchCampaigns = fetchCampaigns;
1241
+ exports.fetchContactInfo = fetchContactInfo;
1242
+ exports.fetchDeveloperInfo = fetchDeveloperInfo;
1243
+ exports.fetchFeatureFlags = fetchFeatureFlags;
1244
+ exports.fetchPaymentOptions = fetchPaymentOptions;
1245
+ exports.fetchProducts = fetchProducts;
1246
+ exports.fetchServices = fetchServices;
1247
+ exports.fetchSkills = fetchSkills;
1248
+ exports.fetchSocialLinks = fetchSocialLinks;
1249
+ exports.fetchTestimonials = fetchTestimonials;
1250
+ exports.getCampaignById = getCampaignById;
1251
+ exports.getCampaignHistory = getCampaignHistory;
1252
+ exports.getConfig = getConfig;
1253
+ exports.getDeviceId = getDeviceId;
1254
+ exports.getEligibleCampaignIds = getEligibleCampaignIds;
1255
+ exports.getFeatureVersion = getFeatureVersion;
1256
+ exports.getProductById = getProductById;
1257
+ exports.getSharedFeaturesApp = getSharedFeaturesApp;
1258
+ exports.getSharedFeaturesAuth = getSharedFeaturesAuth;
1259
+ exports.getSharedFeaturesDb = getSharedFeaturesDb;
1260
+ exports.getSharedFeaturesStatus = getSharedFeaturesStatus;
1261
+ exports.getState = getState;
1262
+ exports.initSharedFeatures = initSharedFeatures;
1263
+ exports.initializeFeatureFlags = initializeFeatureFlags;
1264
+ exports.isEligibleForCampaign = isEligibleForCampaign;
1265
+ exports.isFeatureEnabled = isFeatureEnabled;
1266
+ exports.isInitialized = isInitialized;
1267
+ exports.recordImpression = recordImpression;
1268
+ exports.subscribeToContactInfo = subscribeToContactInfo;
1269
+ exports.subscribeToDeveloperInfo = subscribeToDeveloperInfo;
1270
+ exports.subscribeToFeatureFlags = subscribeToFeatureFlags;
1271
+ exports.trackClick = trackClick;
1272
+ exports.trackClose = trackClose;
1273
+ exports.trackImpression = trackImpression;
1274
+ exports.updateFeatureConfig = updateFeatureConfig;
1275
+ exports.updateGlobalFlags = updateGlobalFlags;
1276
+ //# sourceMappingURL=commonFeatures-CiqxxOin.cjs.map