@rajeev02/deeplink 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.
package/lib/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @rajeev02/deeplink
3
+ * Universal Deep Linking
4
+ * App links, universal links, deferred deep links, route matching, attribution
5
+ *
6
+ * @author Rajeev Kumar Joshi
7
+ * @license MIT
8
+ */
9
+ export { DeepLinkRouter, getCommonRoutes } from "./router";
10
+ export type { DeepLinkRoute, DeepLinkMatch, DeferredDeepLink, DeepLinkConfig, } from "./router";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3D,YAAY,EACV,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,cAAc,GACf,MAAM,UAAU,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCommonRoutes = exports.DeepLinkRouter = void 0;
4
+ /**
5
+ * @rajeev02/deeplink
6
+ * Universal Deep Linking
7
+ * App links, universal links, deferred deep links, route matching, attribution
8
+ *
9
+ * @author Rajeev Kumar Joshi
10
+ * @license MIT
11
+ */
12
+ var router_1 = require("./router");
13
+ Object.defineProperty(exports, "DeepLinkRouter", { enumerable: true, get: function () { return router_1.DeepLinkRouter; } });
14
+ Object.defineProperty(exports, "getCommonRoutes", { enumerable: true, get: function () { return router_1.getCommonRoutes; } });
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA;;;;;;;GAOG;AACH,mCAA2D;AAAlD,wGAAA,cAAc,OAAA;AAAE,yGAAA,eAAe,OAAA"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @rajeev02/deeplink — Router
3
+ * Universal deep link router — pattern matching, parameter extraction,
4
+ * auth guards, deferred deep links, analytics attribution
5
+ */
6
+ export interface DeepLinkRoute {
7
+ /** Pattern: "/product/:id", "/payment/:orderId/status", "/chat/:roomId" */
8
+ pattern: string;
9
+ /** Screen/page name to navigate to */
10
+ screen: string;
11
+ /** Required auth state ('authenticated' | 'any') */
12
+ authRequired?: boolean;
13
+ /** Handler function */
14
+ handler?: (params: Record<string, string>, query: Record<string, string>) => void;
15
+ }
16
+ export interface DeepLinkMatch {
17
+ route: DeepLinkRoute;
18
+ params: Record<string, string>;
19
+ query: Record<string, string>;
20
+ fullUrl: string;
21
+ }
22
+ export interface DeferredDeepLink {
23
+ url: string;
24
+ timestamp: number;
25
+ source?: string;
26
+ campaign?: string;
27
+ processed: boolean;
28
+ }
29
+ export interface DeepLinkConfig {
30
+ /** App scheme (e.g., "rajeevapp://") */
31
+ scheme: string;
32
+ /** Universal link domains (e.g., ["rajeevapp.com", "link.rajeevapp.com"]) */
33
+ domains: string[];
34
+ /** Route definitions */
35
+ routes: DeepLinkRoute[];
36
+ /** Callback when no route matches */
37
+ onNoMatch?: (url: string) => void;
38
+ /** Callback for attribution tracking */
39
+ onAttribution?: (source: string, campaign?: string, medium?: string) => void;
40
+ }
41
+ /**
42
+ * Deep Link Router
43
+ */
44
+ export declare class DeepLinkRouter {
45
+ private config;
46
+ private deferredLink;
47
+ private isReady;
48
+ constructor(config: DeepLinkConfig);
49
+ /** Mark the app as ready to handle deep links (after auth check, navigation ready) */
50
+ setReady(): void;
51
+ /** Handle an incoming deep link URL */
52
+ handle(url: string): DeepLinkMatch | null;
53
+ /** Generate a deep link URL */
54
+ generate(pattern: string, params?: Record<string, string>, query?: Record<string, string>): string;
55
+ /** Generate a universal link (HTTPS) */
56
+ generateUniversalLink(pattern: string, params?: Record<string, string>, query?: Record<string, string>): string;
57
+ /** Get deferred deep link (for cold start handling) */
58
+ getDeferredLink(): DeferredDeepLink | null;
59
+ /** Get all registered routes */
60
+ getRoutes(): DeepLinkRoute[];
61
+ /** Add a route dynamically */
62
+ addRoute(route: DeepLinkRoute): void;
63
+ private parseUrl;
64
+ private matchPattern;
65
+ }
66
+ /**
67
+ * Common deep link routes for super apps
68
+ */
69
+ export declare function getCommonRoutes(): DeepLinkRoute[];
70
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/router/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,aAAa;IAC5B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uBAAuB;IACvB,OAAO,CAAC,EAAE,CACR,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAC1B,IAAI,CAAC;CACX;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,wBAAwB;IACxB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,qCAAqC;IACrC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,wCAAwC;IACxC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9E;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,OAAO,CAAkB;gBAErB,MAAM,EAAE,cAAc;IAIlC,sFAAsF;IACtF,QAAQ,IAAI,IAAI;IAQhB,uCAAuC;IACvC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IA4CzC,+BAA+B;IAC/B,QAAQ,CACN,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACjC,MAAM;IAYT,wCAAwC;IACxC,qBAAqB,CACnB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACjC,MAAM;IAaT,uDAAuD;IACvD,eAAe,IAAI,gBAAgB,GAAG,IAAI;IAI1C,gCAAgC;IAChC,SAAS,IAAI,aAAa,EAAE;IAI5B,8BAA8B;IAC9B,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAIpC,OAAO,CAAC,QAAQ;IAwChB,OAAO,CAAC,YAAY;CAmBrB;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,aAAa,EAAE,CA0CjD"}
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ /**
3
+ * @rajeev02/deeplink — Router
4
+ * Universal deep link router — pattern matching, parameter extraction,
5
+ * auth guards, deferred deep links, analytics attribution
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.DeepLinkRouter = void 0;
9
+ exports.getCommonRoutes = getCommonRoutes;
10
+ /**
11
+ * Deep Link Router
12
+ */
13
+ class DeepLinkRouter {
14
+ constructor(config) {
15
+ this.deferredLink = null;
16
+ this.isReady = false;
17
+ this.config = config;
18
+ }
19
+ /** Mark the app as ready to handle deep links (after auth check, navigation ready) */
20
+ setReady() {
21
+ this.isReady = true;
22
+ if (this.deferredLink && !this.deferredLink.processed) {
23
+ this.handle(this.deferredLink.url);
24
+ this.deferredLink.processed = true;
25
+ }
26
+ }
27
+ /** Handle an incoming deep link URL */
28
+ handle(url) {
29
+ const parsed = this.parseUrl(url);
30
+ if (!parsed)
31
+ return null;
32
+ // Extract UTM params for attribution
33
+ if (parsed.query.utm_source && this.config.onAttribution) {
34
+ this.config.onAttribution(parsed.query.utm_source, parsed.query.utm_campaign, parsed.query.utm_medium);
35
+ }
36
+ // If app not ready yet, defer the link
37
+ if (!this.isReady) {
38
+ this.deferredLink = {
39
+ url,
40
+ timestamp: Date.now(),
41
+ source: parsed.query.utm_source,
42
+ processed: false,
43
+ };
44
+ return null;
45
+ }
46
+ // Match against routes
47
+ for (const route of this.config.routes) {
48
+ const params = this.matchPattern(route.pattern, parsed.path);
49
+ if (params !== null) {
50
+ const match = {
51
+ route,
52
+ params,
53
+ query: parsed.query,
54
+ fullUrl: url,
55
+ };
56
+ if (route.handler)
57
+ route.handler(params, parsed.query);
58
+ return match;
59
+ }
60
+ }
61
+ // No match
62
+ if (this.config.onNoMatch)
63
+ this.config.onNoMatch(url);
64
+ return null;
65
+ }
66
+ /** Generate a deep link URL */
67
+ generate(pattern, params = {}, query = {}) {
68
+ let path = pattern;
69
+ for (const [key, value] of Object.entries(params)) {
70
+ path = path.replace(`:${key}`, encodeURIComponent(value));
71
+ }
72
+ const queryStr = Object.entries(query)
73
+ .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
74
+ .join("&");
75
+ const base = `${this.config.scheme}${path}`;
76
+ return queryStr ? `${base}?${queryStr}` : base;
77
+ }
78
+ /** Generate a universal link (HTTPS) */
79
+ generateUniversalLink(pattern, params = {}, query = {}) {
80
+ let path = pattern;
81
+ for (const [key, value] of Object.entries(params)) {
82
+ path = path.replace(`:${key}`, encodeURIComponent(value));
83
+ }
84
+ const queryStr = Object.entries(query)
85
+ .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
86
+ .join("&");
87
+ const domain = this.config.domains[0] || "app.example.com";
88
+ const base = `https://${domain}${path}`;
89
+ return queryStr ? `${base}?${queryStr}` : base;
90
+ }
91
+ /** Get deferred deep link (for cold start handling) */
92
+ getDeferredLink() {
93
+ return this.deferredLink;
94
+ }
95
+ /** Get all registered routes */
96
+ getRoutes() {
97
+ return [...this.config.routes];
98
+ }
99
+ /** Add a route dynamically */
100
+ addRoute(route) {
101
+ this.config.routes.push(route);
102
+ }
103
+ parseUrl(url) {
104
+ try {
105
+ let path;
106
+ let queryStr = "";
107
+ if (url.includes("://")) {
108
+ const afterScheme = url.split("://")[1] || "";
109
+ // Remove domain for universal links
110
+ let pathPart = afterScheme;
111
+ for (const domain of this.config.domains) {
112
+ if (pathPart.startsWith(domain)) {
113
+ pathPart = pathPart.substring(domain.length);
114
+ break;
115
+ }
116
+ }
117
+ const [p, q] = pathPart.split("?");
118
+ path = p.startsWith("/") ? p : `/${p}`;
119
+ queryStr = q || "";
120
+ }
121
+ else {
122
+ const [p, q] = url.split("?");
123
+ path = p.startsWith("/") ? p : `/${p}`;
124
+ queryStr = q || "";
125
+ }
126
+ const query = {};
127
+ if (queryStr) {
128
+ for (const pair of queryStr.split("&")) {
129
+ const [k, v] = pair.split("=");
130
+ if (k)
131
+ query[decodeURIComponent(k)] = decodeURIComponent(v || "");
132
+ }
133
+ }
134
+ return { path, query };
135
+ }
136
+ catch {
137
+ return null;
138
+ }
139
+ }
140
+ matchPattern(pattern, path) {
141
+ const patternParts = pattern.split("/").filter(Boolean);
142
+ const pathParts = path.split("/").filter(Boolean);
143
+ if (patternParts.length !== pathParts.length)
144
+ return null;
145
+ const params = {};
146
+ for (let i = 0; i < patternParts.length; i++) {
147
+ if (patternParts[i].startsWith(":")) {
148
+ params[patternParts[i].substring(1)] = decodeURIComponent(pathParts[i]);
149
+ }
150
+ else if (patternParts[i] !== pathParts[i]) {
151
+ return null;
152
+ }
153
+ }
154
+ return params;
155
+ }
156
+ }
157
+ exports.DeepLinkRouter = DeepLinkRouter;
158
+ /**
159
+ * Common deep link routes for super apps
160
+ */
161
+ function getCommonRoutes() {
162
+ return [
163
+ { pattern: "/home", screen: "HomeScreen" },
164
+ { pattern: "/product/:id", screen: "ProductScreen" },
165
+ { pattern: "/product/:id/reviews", screen: "ReviewsScreen" },
166
+ { pattern: "/cart", screen: "CartScreen", authRequired: true },
167
+ { pattern: "/checkout", screen: "CheckoutScreen", authRequired: true },
168
+ {
169
+ pattern: "/order/:orderId",
170
+ screen: "OrderDetailScreen",
171
+ authRequired: true,
172
+ },
173
+ {
174
+ pattern: "/order/:orderId/track",
175
+ screen: "OrderTrackingScreen",
176
+ authRequired: true,
177
+ },
178
+ {
179
+ pattern: "/payment/:txnId/status",
180
+ screen: "PaymentStatusScreen",
181
+ authRequired: true,
182
+ },
183
+ { pattern: "/chat/:roomId", screen: "ChatScreen", authRequired: true },
184
+ { pattern: "/profile", screen: "ProfileScreen", authRequired: true },
185
+ {
186
+ pattern: "/profile/settings",
187
+ screen: "SettingsScreen",
188
+ authRequired: true,
189
+ },
190
+ {
191
+ pattern: "/notifications",
192
+ screen: "NotificationsScreen",
193
+ authRequired: true,
194
+ },
195
+ { pattern: "/scan", screen: "QrScanScreen" },
196
+ { pattern: "/pay", screen: "PaymentScreen", authRequired: true },
197
+ { pattern: "/pay/:vpa", screen: "PayToVpaScreen", authRequired: true },
198
+ { pattern: "/refer", screen: "ReferralScreen" },
199
+ { pattern: "/offers", screen: "OffersScreen" },
200
+ { pattern: "/help", screen: "HelpScreen" },
201
+ { pattern: "/kyc", screen: "KycScreen", authRequired: true },
202
+ ];
203
+ }
204
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/router/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@rajeev02/deeplink",
3
+ "version": "0.1.0",
4
+ "description": "Universal deep linking — app links, universal links, deferred deep links, route matching, attribution",
5
+ "main": "lib/index.js",
6
+ "author": "Rajeev Kumar Joshi <rajeevjoshi91@gmail.com> (https://rajeev02.github.io)",
7
+ "license": "MIT",
8
+ "types": "lib/index.d.ts",
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "clean": "rm -rf lib",
12
+ "prepublishOnly": "npm run build"
13
+ },
14
+ "keywords": [
15
+ "react-native",
16
+ "deeplink",
17
+ "universal-links",
18
+ "routing"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/Rajeev02/rajeev-sdk",
23
+ "directory": "packages/deeplink"
24
+ },
25
+ "homepage": "https://github.com/Rajeev02/rajeev-sdk#readme",
26
+ "bugs": {
27
+ "url": "https://github.com/Rajeev02/rajeev-sdk/issues"
28
+ },
29
+ "files": [
30
+ "lib/",
31
+ "src/",
32
+ "README.md"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "peerDependencies": {
38
+ "react": ">=18.3.0",
39
+ "react-native": ">=0.84.0"
40
+ },
41
+ "peerDependenciesMeta": {
42
+ "react-native": {
43
+ "optional": true
44
+ }
45
+ },
46
+ "devDependencies": {
47
+ "@types/react": "^19.0.0",
48
+ "typescript": "^5.4.0"
49
+ }
50
+ }
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @rajeev02/deeplink
3
+ * Universal Deep Linking
4
+ * App links, universal links, deferred deep links, route matching, attribution
5
+ *
6
+ * @author Rajeev Kumar Joshi
7
+ * @license MIT
8
+ */
9
+ export { DeepLinkRouter, getCommonRoutes } from "./router";
10
+ export type {
11
+ DeepLinkRoute,
12
+ DeepLinkMatch,
13
+ DeferredDeepLink,
14
+ DeepLinkConfig,
15
+ } from "./router";
@@ -0,0 +1,271 @@
1
+ /**
2
+ * @rajeev02/deeplink — Router
3
+ * Universal deep link router — pattern matching, parameter extraction,
4
+ * auth guards, deferred deep links, analytics attribution
5
+ */
6
+
7
+ export interface DeepLinkRoute {
8
+ /** Pattern: "/product/:id", "/payment/:orderId/status", "/chat/:roomId" */
9
+ pattern: string;
10
+ /** Screen/page name to navigate to */
11
+ screen: string;
12
+ /** Required auth state ('authenticated' | 'any') */
13
+ authRequired?: boolean;
14
+ /** Handler function */
15
+ handler?: (
16
+ params: Record<string, string>,
17
+ query: Record<string, string>,
18
+ ) => void;
19
+ }
20
+
21
+ export interface DeepLinkMatch {
22
+ route: DeepLinkRoute;
23
+ params: Record<string, string>;
24
+ query: Record<string, string>;
25
+ fullUrl: string;
26
+ }
27
+
28
+ export interface DeferredDeepLink {
29
+ url: string;
30
+ timestamp: number;
31
+ source?: string;
32
+ campaign?: string;
33
+ processed: boolean;
34
+ }
35
+
36
+ export interface DeepLinkConfig {
37
+ /** App scheme (e.g., "rajeevapp://") */
38
+ scheme: string;
39
+ /** Universal link domains (e.g., ["rajeevapp.com", "link.rajeevapp.com"]) */
40
+ domains: string[];
41
+ /** Route definitions */
42
+ routes: DeepLinkRoute[];
43
+ /** Callback when no route matches */
44
+ onNoMatch?: (url: string) => void;
45
+ /** Callback for attribution tracking */
46
+ onAttribution?: (source: string, campaign?: string, medium?: string) => void;
47
+ }
48
+
49
+ /**
50
+ * Deep Link Router
51
+ */
52
+ export class DeepLinkRouter {
53
+ private config: DeepLinkConfig;
54
+ private deferredLink: DeferredDeepLink | null = null;
55
+ private isReady: boolean = false;
56
+
57
+ constructor(config: DeepLinkConfig) {
58
+ this.config = config;
59
+ }
60
+
61
+ /** Mark the app as ready to handle deep links (after auth check, navigation ready) */
62
+ setReady(): void {
63
+ this.isReady = true;
64
+ if (this.deferredLink && !this.deferredLink.processed) {
65
+ this.handle(this.deferredLink.url);
66
+ this.deferredLink.processed = true;
67
+ }
68
+ }
69
+
70
+ /** Handle an incoming deep link URL */
71
+ handle(url: string): DeepLinkMatch | null {
72
+ const parsed = this.parseUrl(url);
73
+ if (!parsed) return null;
74
+
75
+ // Extract UTM params for attribution
76
+ if (parsed.query.utm_source && this.config.onAttribution) {
77
+ this.config.onAttribution(
78
+ parsed.query.utm_source,
79
+ parsed.query.utm_campaign,
80
+ parsed.query.utm_medium,
81
+ );
82
+ }
83
+
84
+ // If app not ready yet, defer the link
85
+ if (!this.isReady) {
86
+ this.deferredLink = {
87
+ url,
88
+ timestamp: Date.now(),
89
+ source: parsed.query.utm_source,
90
+ processed: false,
91
+ };
92
+ return null;
93
+ }
94
+
95
+ // Match against routes
96
+ for (const route of this.config.routes) {
97
+ const params = this.matchPattern(route.pattern, parsed.path);
98
+ if (params !== null) {
99
+ const match: DeepLinkMatch = {
100
+ route,
101
+ params,
102
+ query: parsed.query,
103
+ fullUrl: url,
104
+ };
105
+ if (route.handler) route.handler(params, parsed.query);
106
+ return match;
107
+ }
108
+ }
109
+
110
+ // No match
111
+ if (this.config.onNoMatch) this.config.onNoMatch(url);
112
+ return null;
113
+ }
114
+
115
+ /** Generate a deep link URL */
116
+ generate(
117
+ pattern: string,
118
+ params: Record<string, string> = {},
119
+ query: Record<string, string> = {},
120
+ ): string {
121
+ let path = pattern;
122
+ for (const [key, value] of Object.entries(params)) {
123
+ path = path.replace(`:${key}`, encodeURIComponent(value));
124
+ }
125
+ const queryStr = Object.entries(query)
126
+ .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
127
+ .join("&");
128
+ const base = `${this.config.scheme}${path}`;
129
+ return queryStr ? `${base}?${queryStr}` : base;
130
+ }
131
+
132
+ /** Generate a universal link (HTTPS) */
133
+ generateUniversalLink(
134
+ pattern: string,
135
+ params: Record<string, string> = {},
136
+ query: Record<string, string> = {},
137
+ ): string {
138
+ let path = pattern;
139
+ for (const [key, value] of Object.entries(params)) {
140
+ path = path.replace(`:${key}`, encodeURIComponent(value));
141
+ }
142
+ const queryStr = Object.entries(query)
143
+ .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
144
+ .join("&");
145
+ const domain = this.config.domains[0] || "app.example.com";
146
+ const base = `https://${domain}${path}`;
147
+ return queryStr ? `${base}?${queryStr}` : base;
148
+ }
149
+
150
+ /** Get deferred deep link (for cold start handling) */
151
+ getDeferredLink(): DeferredDeepLink | null {
152
+ return this.deferredLink;
153
+ }
154
+
155
+ /** Get all registered routes */
156
+ getRoutes(): DeepLinkRoute[] {
157
+ return [...this.config.routes];
158
+ }
159
+
160
+ /** Add a route dynamically */
161
+ addRoute(route: DeepLinkRoute): void {
162
+ this.config.routes.push(route);
163
+ }
164
+
165
+ private parseUrl(
166
+ url: string,
167
+ ): { path: string; query: Record<string, string> } | null {
168
+ try {
169
+ let path: string;
170
+ let queryStr: string = "";
171
+
172
+ if (url.includes("://")) {
173
+ const afterScheme = url.split("://")[1] || "";
174
+ // Remove domain for universal links
175
+ let pathPart = afterScheme;
176
+ for (const domain of this.config.domains) {
177
+ if (pathPart.startsWith(domain)) {
178
+ pathPart = pathPart.substring(domain.length);
179
+ break;
180
+ }
181
+ }
182
+ const [p, q] = pathPart.split("?");
183
+ path = p.startsWith("/") ? p : `/${p}`;
184
+ queryStr = q || "";
185
+ } else {
186
+ const [p, q] = url.split("?");
187
+ path = p.startsWith("/") ? p : `/${p}`;
188
+ queryStr = q || "";
189
+ }
190
+
191
+ const query: Record<string, string> = {};
192
+ if (queryStr) {
193
+ for (const pair of queryStr.split("&")) {
194
+ const [k, v] = pair.split("=");
195
+ if (k) query[decodeURIComponent(k)] = decodeURIComponent(v || "");
196
+ }
197
+ }
198
+
199
+ return { path, query };
200
+ } catch {
201
+ return null;
202
+ }
203
+ }
204
+
205
+ private matchPattern(
206
+ pattern: string,
207
+ path: string,
208
+ ): Record<string, string> | null {
209
+ const patternParts = pattern.split("/").filter(Boolean);
210
+ const pathParts = path.split("/").filter(Boolean);
211
+
212
+ if (patternParts.length !== pathParts.length) return null;
213
+
214
+ const params: Record<string, string> = {};
215
+ for (let i = 0; i < patternParts.length; i++) {
216
+ if (patternParts[i].startsWith(":")) {
217
+ params[patternParts[i].substring(1)] = decodeURIComponent(pathParts[i]);
218
+ } else if (patternParts[i] !== pathParts[i]) {
219
+ return null;
220
+ }
221
+ }
222
+ return params;
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Common deep link routes for super apps
228
+ */
229
+ export function getCommonRoutes(): DeepLinkRoute[] {
230
+ return [
231
+ { pattern: "/home", screen: "HomeScreen" },
232
+ { pattern: "/product/:id", screen: "ProductScreen" },
233
+ { pattern: "/product/:id/reviews", screen: "ReviewsScreen" },
234
+ { pattern: "/cart", screen: "CartScreen", authRequired: true },
235
+ { pattern: "/checkout", screen: "CheckoutScreen", authRequired: true },
236
+ {
237
+ pattern: "/order/:orderId",
238
+ screen: "OrderDetailScreen",
239
+ authRequired: true,
240
+ },
241
+ {
242
+ pattern: "/order/:orderId/track",
243
+ screen: "OrderTrackingScreen",
244
+ authRequired: true,
245
+ },
246
+ {
247
+ pattern: "/payment/:txnId/status",
248
+ screen: "PaymentStatusScreen",
249
+ authRequired: true,
250
+ },
251
+ { pattern: "/chat/:roomId", screen: "ChatScreen", authRequired: true },
252
+ { pattern: "/profile", screen: "ProfileScreen", authRequired: true },
253
+ {
254
+ pattern: "/profile/settings",
255
+ screen: "SettingsScreen",
256
+ authRequired: true,
257
+ },
258
+ {
259
+ pattern: "/notifications",
260
+ screen: "NotificationsScreen",
261
+ authRequired: true,
262
+ },
263
+ { pattern: "/scan", screen: "QrScanScreen" },
264
+ { pattern: "/pay", screen: "PaymentScreen", authRequired: true },
265
+ { pattern: "/pay/:vpa", screen: "PayToVpaScreen", authRequired: true },
266
+ { pattern: "/refer", screen: "ReferralScreen" },
267
+ { pattern: "/offers", screen: "OffersScreen" },
268
+ { pattern: "/help", screen: "HelpScreen" },
269
+ { pattern: "/kyc", screen: "KycScreen", authRequired: true },
270
+ ];
271
+ }