@mohasinac/appkit 2.5.1 → 2.6.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.
package/dist/jobs.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `@mohasinac/appkit/jobs` — Firebase Functions binders + job handlers.
3
+ *
4
+ * Carved out of `server-entry.ts` 2026-05-12 because the import chain reaches
5
+ * `firebase-functions/v2/{https,scheduler,firestore}`, which is only
6
+ * available in the Firebase Functions runtime — not in Vercel Next.js
7
+ * lambdas. Re-exporting these from the main server surface forced every
8
+ * consumer (including the letitrip Next app) to install `firebase-functions`
9
+ * as a dep just to get past `next build`.
10
+ *
11
+ * Now: only the `appkit/functions/` package imports this subpath. The
12
+ * letitrip Next app never reaches `firebase-functions` because it's not in
13
+ * any of the chains rooted at `@mohasinac/appkit` or
14
+ * `@mohasinac/appkit/server`.
15
+ *
16
+ * Usage (functions/src/index.ts):
17
+ * import {
18
+ * bindToFirebase,
19
+ * couponExpiryHandler,
20
+ * listingProcessorHandler,
21
+ * } from "@mohasinac/appkit/jobs";
22
+ */
23
+ export { couponExpiryHandler, offerExpiryHandler, cartPruneHandler, notificationPruneHandler, dailyDataCleanupHandler, cleanupRtdbEventsHandler, auctionSettlementHandler, autoPayoutEligibilityHandler, countersReconcileHandler, onOrderCreateHandler, onOrderStatusChangeHandler, onBidPlacedHandler, onReviewWriteHandler, promotionsHandler, mediaTmpCleanupHandler, pendingOrderTimeoutHandler, productStatsSyncHandler, positionsReconcileHandler, payoutBatchHandler, weeklyPayoutEligibilityHandler, onCategoryWriteHandler, onProductWriteHandler, onStoreWriteHandler, adminAnalyticsHandler, storeAnalyticsHandler, listingProcessorHandler, supportedListingCollections, bindSchedule, bindDocumentWritten, bindDocumentCreated, bindDocumentUpdated, bindCallable, bindHttps, bindToFirebase, } from "./_internal/server/jobs/index.js";
24
+ export type { PromotionsCallableResult, AdminAnalyticsResult, StoreAnalyticsInput, StoreAnalyticsResult, ListingRequestBody, ListingResponseBody, JobContext, JobLogger, JobHandlers, ScheduleHandler, FirestoreTriggerHandler, FirestoreTriggerEvent, CallableHandler, BindHttpsOptions, } from "./_internal/server/jobs/index.js";
package/dist/jobs.js ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * `@mohasinac/appkit/jobs` — Firebase Functions binders + job handlers.
3
+ *
4
+ * Carved out of `server-entry.ts` 2026-05-12 because the import chain reaches
5
+ * `firebase-functions/v2/{https,scheduler,firestore}`, which is only
6
+ * available in the Firebase Functions runtime — not in Vercel Next.js
7
+ * lambdas. Re-exporting these from the main server surface forced every
8
+ * consumer (including the letitrip Next app) to install `firebase-functions`
9
+ * as a dep just to get past `next build`.
10
+ *
11
+ * Now: only the `appkit/functions/` package imports this subpath. The
12
+ * letitrip Next app never reaches `firebase-functions` because it's not in
13
+ * any of the chains rooted at `@mohasinac/appkit` or
14
+ * `@mohasinac/appkit/server`.
15
+ *
16
+ * Usage (functions/src/index.ts):
17
+ * import {
18
+ * bindToFirebase,
19
+ * couponExpiryHandler,
20
+ * listingProcessorHandler,
21
+ * } from "@mohasinac/appkit/jobs";
22
+ */
23
+ export {
24
+ // S4–S5: Job handlers (pure, framework-agnostic)
25
+ couponExpiryHandler, offerExpiryHandler, cartPruneHandler, notificationPruneHandler, dailyDataCleanupHandler, cleanupRtdbEventsHandler, auctionSettlementHandler, autoPayoutEligibilityHandler, countersReconcileHandler, onOrderCreateHandler, onOrderStatusChangeHandler, onBidPlacedHandler, onReviewWriteHandler, promotionsHandler, mediaTmpCleanupHandler, pendingOrderTimeoutHandler, productStatsSyncHandler, positionsReconcileHandler, payoutBatchHandler, weeklyPayoutEligibilityHandler, onCategoryWriteHandler, onProductWriteHandler, onStoreWriteHandler, adminAnalyticsHandler, storeAnalyticsHandler, listingProcessorHandler, supportedListingCollections,
26
+ // Firebase binder adapter
27
+ bindSchedule, bindDocumentWritten, bindDocumentCreated, bindDocumentUpdated, bindCallable, bindHttps, bindToFirebase, } from "./_internal/server/jobs/index.js";
@@ -128,10 +128,12 @@ export function createRouteHandler(options) {
128
128
  return response;
129
129
  }
130
130
  catch (err) {
131
- // Structured errors thrown with .status
132
- const status = typeof err?.status === "number"
133
- ? err.status
134
- : 500;
131
+ const e = err;
132
+ const status = typeof e?.statusCode === "number"
133
+ ? e.statusCode
134
+ : typeof e?.status === "number"
135
+ ? e.status
136
+ : 500;
135
137
  const message = err instanceof Error ? err.message : "Internal server error";
136
138
  // 401/403 are expected for protected routes and should not be error-noisy.
137
139
  if (status >= 500) {
@@ -36,8 +36,6 @@ export { createCheckoutOrderAction, attachPaymentAction, formatShippingAddress,
36
36
  export { createPaymentIntentAction, verifyPaymentSignatureAction, resolvePaymentFee, PAYMENTS_DEFAULT_RAZORPAY_FEE_PERCENT, PAYMENTS_RECEIPT_PREFIX, type CreatePaymentIntentInput, type CreatePaymentIntentResult, type VerifyPaymentSignatureInput, type ResolvedPaymentFee, } from "./_internal/server/features/payments/index";
37
37
  export { getSublistingCategoryForDetail } from "./_internal/server/features/sublisting-categories/index";
38
38
  export { getStoreForDetail, listStoreProductsInitial, listStoreAuctionsInitial, listStorePreOrdersInitial, listSitemapStores, STORES_PAGE_SIZE, STORES_PRODUCTS_PAGE_SIZE, STORES_SITEMAP_LIMIT, STORES_FEATURED_LIMIT, } from "./_internal/server/features/stores/index";
39
- export { couponExpiryHandler, offerExpiryHandler, cartPruneHandler, notificationPruneHandler, dailyDataCleanupHandler, cleanupRtdbEventsHandler, auctionSettlementHandler, autoPayoutEligibilityHandler, countersReconcileHandler, onOrderCreateHandler, onOrderStatusChangeHandler, onBidPlacedHandler, onReviewWriteHandler, promotionsHandler, type PromotionsCallableResult, mediaTmpCleanupHandler, pendingOrderTimeoutHandler, productStatsSyncHandler, positionsReconcileHandler, payoutBatchHandler, weeklyPayoutEligibilityHandler, onCategoryWriteHandler, onProductWriteHandler, onStoreWriteHandler, adminAnalyticsHandler, type AdminAnalyticsResult, storeAnalyticsHandler, type StoreAnalyticsInput, type StoreAnalyticsResult, listingProcessorHandler, supportedListingCollections, type ListingRequestBody, type ListingResponseBody, bindSchedule, bindDocumentWritten, bindDocumentCreated, bindDocumentUpdated, bindCallable, bindHttps, bindToFirebase, } from "./_internal/server/jobs/index";
40
- export type { JobContext, JobLogger, JobHandlers, ScheduleHandler, FirestoreTriggerHandler, FirestoreTriggerEvent, CallableHandler, } from "./_internal/server/jobs/index";
41
39
  export { AppShell, DashboardScaffold } from "./_internal/client/scaffolds/index";
42
40
  export type { AppShellProps, AppShellRenderContext, DashboardScaffoldProps, DashboardScaffoldRenderContext, } from "./_internal/client/scaffolds/index";
43
41
  export { toClient, clientInitial } from "./_internal/shared/serialization/index";
@@ -62,8 +62,11 @@ export { createPaymentIntentAction, verifyPaymentSignatureAction, resolvePayment
62
62
  export { getSublistingCategoryForDetail } from "./_internal/server/features/sublisting-categories/index";
63
63
  // S3: stores data layer
64
64
  export { getStoreForDetail, listStoreProductsInitial, listStoreAuctionsInitial, listStorePreOrdersInitial, listSitemapStores, STORES_PAGE_SIZE, STORES_PRODUCTS_PAGE_SIZE, STORES_SITEMAP_LIMIT, STORES_FEATURED_LIMIT, } from "./_internal/server/features/stores/index";
65
- // S4–S5: Job handlers + runtime (dormant until consumer's functions/ wires them via bindToFirebase)
66
- export { couponExpiryHandler, offerExpiryHandler, cartPruneHandler, notificationPruneHandler, dailyDataCleanupHandler, cleanupRtdbEventsHandler, auctionSettlementHandler, autoPayoutEligibilityHandler, countersReconcileHandler, onOrderCreateHandler, onOrderStatusChangeHandler, onBidPlacedHandler, onReviewWriteHandler, promotionsHandler, mediaTmpCleanupHandler, pendingOrderTimeoutHandler, productStatsSyncHandler, positionsReconcileHandler, payoutBatchHandler, weeklyPayoutEligibilityHandler, onCategoryWriteHandler, onProductWriteHandler, onStoreWriteHandler, adminAnalyticsHandler, storeAnalyticsHandler, listingProcessorHandler, supportedListingCollections, bindSchedule, bindDocumentWritten, bindDocumentCreated, bindDocumentUpdated, bindCallable, bindHttps, bindToFirebase, } from "./_internal/server/jobs/index";
65
+ // S4–S5: Job handlers + Firebase binders moved to the `@mohasinac/appkit/jobs`
66
+ // subpath (2.6.0, 2026-05-12). The chain reaches `firebase-functions/v2/*`
67
+ // which is only available in the Firebase Functions runtime, not in Vercel
68
+ // Next.js lambdas. Consumers that need them (i.e. `functions/src/index.ts`)
69
+ // import directly from `@mohasinac/appkit/jobs`.
67
70
  // S6: client scaffolds (server-side type-aware import; runtime is "use client")
68
71
  export { AppShell, DashboardScaffold } from "./_internal/client/scaffolds/index";
69
72
  // CC-3: hydration helpers
@@ -1,7 +1,19 @@
1
+ "use client";
1
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React from "react";
3
+ import React, { useCallback } from "react";
3
4
  import { twMerge } from "tailwind-merge";
4
5
  import { Loader2 } from "lucide-react";
6
+ function spawnRipple(host, clientX, clientY) {
7
+ const rect = host.getBoundingClientRect();
8
+ const size = Math.max(rect.width, rect.height);
9
+ const ripple = document.createElement("span");
10
+ ripple.className = "appkit-button__ripple";
11
+ ripple.style.width = ripple.style.height = `${size}px`;
12
+ ripple.style.left = `${clientX - rect.left - size / 2}px`;
13
+ ripple.style.top = `${clientY - rect.top - size / 2}px`;
14
+ host.appendChild(ripple);
15
+ ripple.addEventListener("animationend", () => ripple.remove(), { once: true });
16
+ }
5
17
  /**
6
18
  * Button — versatile button with multiple variants, sizes, and loading state.
7
19
  *
@@ -27,6 +39,13 @@ const UI_BUTTON = {
27
39
  };
28
40
  export function Button({ variant = "primary", size = "md", className = "", isLoading = false, disabled, children, asChild = false, ...props }) {
29
41
  const classes = twMerge(UI_BUTTON.base, UI_BUTTON.variants[variant], UI_BUTTON.sizes[size], className);
42
+ const userOnClick = props.onClick;
43
+ const handleClick = useCallback((event) => {
44
+ if (!disabled && !isLoading) {
45
+ spawnRipple(event.currentTarget, event.clientX, event.clientY);
46
+ }
47
+ userOnClick?.(event);
48
+ }, [disabled, isLoading, userOnClick]);
30
49
  if (asChild && React.isValidElement(children)) {
31
50
  const child = children;
32
51
  return React.cloneElement(child, {
@@ -35,5 +54,5 @@ export function Button({ variant = "primary", size = "md", className = "", isLoa
35
54
  ...(disabled ? { "aria-disabled": true } : {}),
36
55
  });
37
56
  }
38
- return (_jsxs("button", { className: classes, disabled: disabled || isLoading, "aria-busy": isLoading || undefined, ...props, children: [isLoading && (_jsx(Loader2, { className: "appkit-button__spinner", "aria-hidden": "true" })), isLoading ? (_jsx("span", { className: "appkit-button__content appkit-button__content--loading", children: children })) : (_jsx("span", { className: "appkit-button__content", children: children }))] }));
57
+ return (_jsxs("button", { className: classes, disabled: disabled || isLoading, "aria-busy": isLoading || undefined, ...props, onClick: handleClick, children: [isLoading && (_jsx(Loader2, { className: "appkit-button__spinner", "aria-hidden": "true" })), isLoading ? (_jsx("span", { className: "appkit-button__content appkit-button__content--loading", children: children })) : (_jsx("span", { className: "appkit-button__content", children: children }))] }));
39
58
  }
@@ -11,6 +11,40 @@
11
11
  transition: all 0.2s ease;
12
12
  cursor: pointer;
13
13
  user-select: none;
14
+ position: relative;
15
+ overflow: hidden;
16
+ isolation: isolate;
17
+ }
18
+
19
+ .appkit-button__ripple {
20
+ position: absolute;
21
+ border-radius: 9999px;
22
+ background: currentColor;
23
+ opacity: 0.28;
24
+ pointer-events: none;
25
+ transform: scale(0);
26
+ animation: appkit-button-ripple 520ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
27
+ z-index: 0;
28
+ }
29
+
30
+ .appkit-button__content,
31
+ .appkit-button__spinner {
32
+ position: relative;
33
+ z-index: 1;
34
+ }
35
+
36
+ @keyframes appkit-button-ripple {
37
+ to {
38
+ transform: scale(2.4);
39
+ opacity: 0;
40
+ }
41
+ }
42
+
43
+ @media (prefers-reduced-motion: reduce) {
44
+ .appkit-button__ripple {
45
+ animation-duration: 1ms;
46
+ opacity: 0;
47
+ }
14
48
  }
15
49
 
16
50
  .appkit-button:focus-visible {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mohasinac/appkit",
3
- "version": "2.5.1",
3
+ "version": "2.6.1",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -39,6 +39,10 @@
39
39
  "types": "./dist/server.d.ts",
40
40
  "import": "./dist/server.js"
41
41
  },
42
+ "./jobs": {
43
+ "types": "./dist/jobs.d.ts",
44
+ "import": "./dist/jobs.js"
45
+ },
42
46
  "./providers": {
43
47
  "types": "./dist/providers.d.ts",
44
48
  "import": "./dist/providers.js"