roblox-deeplink-parser 0.1.23 → 0.1.25
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/AuthedProtocolParser.d.ts +86 -0
- package/dist/AuthedProtocolParser.js +147 -0
- package/dist/DeepLinkParser.d.ts +82 -0
- package/dist/DeepLinkParser.js +1293 -0
- package/dist/shared/chunk-pqjz2eep.js +13 -0
- package/package.json +8 -9
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
type AuthedProtocolUrls<T> = {
|
|
2
|
+
robloxPlayerProtocol: T;
|
|
3
|
+
robloxStudioProtocol: T;
|
|
4
|
+
robloxStudioAuthProtocol: T;
|
|
5
|
+
placeLauncherUrl: string;
|
|
6
|
+
};
|
|
7
|
+
type AuthedProtocolParserConstructorProps<T extends string> = {
|
|
8
|
+
urls?: Partial<AuthedProtocolUrls<T>>;
|
|
9
|
+
};
|
|
10
|
+
type AuthedLaunchMode = "edit" | "plugin" | "play" | "build" | "app" | "asset";
|
|
11
|
+
type AuthLaunchExp = "InApp" | "PreferInApp" | "InBrowser";
|
|
12
|
+
type AuthedStudioTask = "EditFile" | "EditPlace" | "EditPlaceRevision" | "StartClient" | "StartTeamTest" | "InstallPlugin" | "TryAsset" | "RemoteDebug" | "StartServer";
|
|
13
|
+
type AuthedDistributorType = "Global" | "ChinaJoinVenture";
|
|
14
|
+
type AuthedOtherParams = {
|
|
15
|
+
browsertrackerid?: number;
|
|
16
|
+
robloxLocale?: string;
|
|
17
|
+
gameLocale?: string;
|
|
18
|
+
channel?: string;
|
|
19
|
+
LaunchExp?: AuthLaunchExp;
|
|
20
|
+
avatar?: string;
|
|
21
|
+
assetid?: number;
|
|
22
|
+
pluginid?: number;
|
|
23
|
+
placeid?: number;
|
|
24
|
+
universeid?: number;
|
|
25
|
+
script?: string;
|
|
26
|
+
placelauncherurl?: string;
|
|
27
|
+
task?: AuthedStudioTask;
|
|
28
|
+
traceId?: string;
|
|
29
|
+
userId?: number;
|
|
30
|
+
browser?: string;
|
|
31
|
+
distributorType?: AuthedDistributorType;
|
|
32
|
+
[key: string]: string | number | undefined;
|
|
33
|
+
};
|
|
34
|
+
type BuildAuthedProtocolUrlParameters<T extends string> = {
|
|
35
|
+
type: T;
|
|
36
|
+
launchMode?: AuthedLaunchMode;
|
|
37
|
+
gameInfo?: string;
|
|
38
|
+
launchTime?: string;
|
|
39
|
+
baseUrl?: string;
|
|
40
|
+
otherParams?: AuthedOtherParams;
|
|
41
|
+
state?: string;
|
|
42
|
+
code?: string;
|
|
43
|
+
};
|
|
44
|
+
type BuildAuthedPlaceLauncherRequest = "RequestGame" | "RequestCloudEdit" | "RequestGameJob" | "RequestFollowUser" | "RequestPrivateGame" | "RequestPlayTogetherGame" | "RequestGameApp" | "RequestInvalid" | "RequestPlayWithParty" | "CheckGameJobStatus" | "RequestReservedGame" | "RequestCrossExpVoice";
|
|
45
|
+
type AuthedPrivateGameMode = "ReservedServer";
|
|
46
|
+
type BuildAuthedPlaceLauncherURLParameters<T extends string> = {
|
|
47
|
+
request: BuildAuthedPlaceLauncherRequest;
|
|
48
|
+
placeId?: number;
|
|
49
|
+
jobId?: string;
|
|
50
|
+
gameId?: string;
|
|
51
|
+
gender?: string;
|
|
52
|
+
genderId?: number;
|
|
53
|
+
accessCode?: string;
|
|
54
|
+
linkCode?: string;
|
|
55
|
+
launchData?: string;
|
|
56
|
+
privateGameMode?: AuthedPrivateGameMode;
|
|
57
|
+
teleportType?: string;
|
|
58
|
+
reservedServerAccessCode?: string;
|
|
59
|
+
referralPage?: string;
|
|
60
|
+
referredByPlayerId?: number;
|
|
61
|
+
conversationId?: number;
|
|
62
|
+
isPartyLeader?: boolean;
|
|
63
|
+
isTeleport?: boolean;
|
|
64
|
+
partyGuid?: string;
|
|
65
|
+
isPlayTogetherGame?: boolean;
|
|
66
|
+
joinAttemptId?: string;
|
|
67
|
+
joinAttemptOrigin?: T;
|
|
68
|
+
callId?: string;
|
|
69
|
+
browserTrackerId?: number;
|
|
70
|
+
eventId?: string;
|
|
71
|
+
isolationContext?: string;
|
|
72
|
+
gameJoinContext?: string;
|
|
73
|
+
userId?: number;
|
|
74
|
+
};
|
|
75
|
+
declare class AuthedProtocolParser<
|
|
76
|
+
T extends string,
|
|
77
|
+
U extends string
|
|
78
|
+
> {
|
|
79
|
+
_urls: AuthedProtocolUrls<T>;
|
|
80
|
+
constructor(props?: AuthedProtocolParserConstructorProps<T>);
|
|
81
|
+
buildAuthedProtocolUrl(request: BuildAuthedProtocolUrlParameters<T>): string;
|
|
82
|
+
buildAuthedPlaceLauncherUrl(request: BuildAuthedPlaceLauncherURLParameters<U>): string;
|
|
83
|
+
parseAuthedProtocolUrl(url: string): BuildAuthedProtocolUrlParameters<T> | null;
|
|
84
|
+
parseAuthedPlaceLauncherUrl(urlStr: string): BuildAuthedPlaceLauncherURLParameters<U> | null;
|
|
85
|
+
}
|
|
86
|
+
export { AuthedProtocolParser as default, BuildAuthedProtocolUrlParameters, BuildAuthedPlaceLauncherURLParameters, BuildAuthedPlaceLauncherRequest, AuthedStudioTask, AuthedProtocolUrls, AuthedProtocolParserConstructorProps, AuthedPrivateGameMode, AuthedOtherParams, AuthedLaunchMode, AuthedDistributorType, AuthLaunchExp };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_PLACELAUNCHER_URL,
|
|
3
|
+
DEFAULT_ROBLOX_PLAYER_AUTHED_PROTOCOL,
|
|
4
|
+
DEFAULT_ROBLOX_STUDIO_AUTHED_PROTOCOL,
|
|
5
|
+
DEFAULT_ROBLOX_STUDIO_AUTH_AUTHED_PROTOCOL
|
|
6
|
+
} from "./shared/chunk-pqjz2eep.js";
|
|
7
|
+
|
|
8
|
+
// src/AuthedProtocolParser.ts
|
|
9
|
+
class AuthedProtocolParser {
|
|
10
|
+
_urls = {
|
|
11
|
+
robloxPlayerProtocol: DEFAULT_ROBLOX_PLAYER_AUTHED_PROTOCOL,
|
|
12
|
+
robloxStudioProtocol: DEFAULT_ROBLOX_STUDIO_AUTHED_PROTOCOL,
|
|
13
|
+
robloxStudioAuthProtocol: DEFAULT_ROBLOX_STUDIO_AUTH_AUTHED_PROTOCOL,
|
|
14
|
+
placeLauncherUrl: DEFAULT_PLACELAUNCHER_URL
|
|
15
|
+
};
|
|
16
|
+
constructor(props) {
|
|
17
|
+
if (props?.urls) {
|
|
18
|
+
if (props.urls.robloxPlayerProtocol) {
|
|
19
|
+
this._urls.robloxPlayerProtocol = props.urls.robloxPlayerProtocol;
|
|
20
|
+
}
|
|
21
|
+
if (props.urls.robloxStudioProtocol) {
|
|
22
|
+
this._urls.robloxStudioProtocol = props.urls.robloxStudioProtocol;
|
|
23
|
+
}
|
|
24
|
+
if (props.urls.robloxStudioAuthProtocol) {
|
|
25
|
+
this._urls.robloxStudioAuthProtocol = props.urls.robloxStudioAuthProtocol;
|
|
26
|
+
}
|
|
27
|
+
if (props.urls.placeLauncherUrl) {
|
|
28
|
+
this._urls.placeLauncherUrl = props.urls.placeLauncherUrl;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
buildAuthedProtocolUrl(request) {
|
|
33
|
+
if (request.type === this._urls.robloxStudioAuthProtocol && request.state && request.code) {
|
|
34
|
+
return `${this._urls.robloxStudioAuthProtocol}://?state=${request.state}&code=${request.code}`;
|
|
35
|
+
}
|
|
36
|
+
const params = ["1"];
|
|
37
|
+
if (request.launchMode)
|
|
38
|
+
params.push(`launchmode:${request.launchMode}`);
|
|
39
|
+
if (request.gameInfo)
|
|
40
|
+
params.push(`gameinfo:${request.gameInfo}`);
|
|
41
|
+
if (request.launchTime)
|
|
42
|
+
params.push(`launchtime:${request.launchTime}`);
|
|
43
|
+
if (request.baseUrl)
|
|
44
|
+
params.push(`baseUrl:${request.baseUrl}`);
|
|
45
|
+
if (request.otherParams) {
|
|
46
|
+
for (const key in request.otherParams) {
|
|
47
|
+
const value = request.otherParams[key];
|
|
48
|
+
if (key === value) {
|
|
49
|
+
params.push(key);
|
|
50
|
+
} else if (value !== undefined && value !== null) {
|
|
51
|
+
params.push(`${key}:${encodeURIComponent(value)}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return `${request.type}:${params.join("+")}`;
|
|
56
|
+
}
|
|
57
|
+
buildAuthedPlaceLauncherUrl(request) {
|
|
58
|
+
const url = new URL(this._urls.placeLauncherUrl);
|
|
59
|
+
const stringifiedParameters = {};
|
|
60
|
+
for (const key in request) {
|
|
61
|
+
const value = request[key];
|
|
62
|
+
if (value !== undefined && value !== null) {
|
|
63
|
+
stringifiedParameters[key] = String(value);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
url.search = new URLSearchParams(stringifiedParameters).toString();
|
|
67
|
+
return url.toString();
|
|
68
|
+
}
|
|
69
|
+
parseAuthedProtocolUrl(url) {
|
|
70
|
+
if (url.startsWith(`${this._urls.robloxStudioAuthProtocol}:`)) {
|
|
71
|
+
const urlObj = new URL(url);
|
|
72
|
+
return {
|
|
73
|
+
type: this._urls.robloxStudioAuthProtocol,
|
|
74
|
+
state: urlObj.searchParams.get("state") ?? undefined,
|
|
75
|
+
code: urlObj.searchParams.get("code") ?? undefined
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const isPlayer = url.startsWith(`${this._urls.robloxPlayerProtocol}:1`);
|
|
79
|
+
const isStudio = url.startsWith(`${this._urls.robloxStudioProtocol}:1`);
|
|
80
|
+
if (!isPlayer && !isStudio) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const split = url.split("+");
|
|
84
|
+
const type = isPlayer ? this._urls.robloxPlayerProtocol : this._urls.robloxStudioProtocol;
|
|
85
|
+
const params = {
|
|
86
|
+
type
|
|
87
|
+
};
|
|
88
|
+
for (let i = 1;i < split.length; i++) {
|
|
89
|
+
const item = split[i];
|
|
90
|
+
const [key, value] = item.split(":");
|
|
91
|
+
if (!value)
|
|
92
|
+
continue;
|
|
93
|
+
switch (key.toLowerCase()) {
|
|
94
|
+
case "launchmode": {
|
|
95
|
+
params.launchMode = value;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case "gameinfo": {
|
|
99
|
+
params.gameInfo = value;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case "launchtime": {
|
|
103
|
+
params.launchTime = value;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
default: {
|
|
107
|
+
params.otherParams ??= {};
|
|
108
|
+
params.otherParams[key] = decodeURIComponent(value);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return params;
|
|
113
|
+
}
|
|
114
|
+
parseAuthedPlaceLauncherUrl(urlStr) {
|
|
115
|
+
try {
|
|
116
|
+
const url = new URL(urlStr);
|
|
117
|
+
const request = url.searchParams.get("request");
|
|
118
|
+
if (!request)
|
|
119
|
+
return null;
|
|
120
|
+
const obj = {
|
|
121
|
+
request
|
|
122
|
+
};
|
|
123
|
+
for (const [key, value] of url.searchParams) {
|
|
124
|
+
let valueToSet;
|
|
125
|
+
if (value === "true") {
|
|
126
|
+
valueToSet = true;
|
|
127
|
+
} else if (value === "false") {
|
|
128
|
+
valueToSet = false;
|
|
129
|
+
} else {
|
|
130
|
+
const parsedNumber = Number(value);
|
|
131
|
+
if (!Number.isNaN(parsedNumber)) {
|
|
132
|
+
valueToSet = parsedNumber;
|
|
133
|
+
} else {
|
|
134
|
+
valueToSet = value;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
obj[key] = valueToSet;
|
|
138
|
+
}
|
|
139
|
+
return obj;
|
|
140
|
+
} catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
AuthedProtocolParser as default
|
|
147
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
type DeepLinkUrlQueryParameter<T extends string | number | symbol> = {
|
|
2
|
+
regex?: RegExp;
|
|
3
|
+
required?: boolean | string;
|
|
4
|
+
} & ({
|
|
5
|
+
name: T;
|
|
6
|
+
} | {
|
|
7
|
+
name: string;
|
|
8
|
+
mappedName: T;
|
|
9
|
+
});
|
|
10
|
+
type DeepLinkUrlPathParameter<T extends string | number | symbol> = {
|
|
11
|
+
name: T;
|
|
12
|
+
};
|
|
13
|
+
type DeepLinkUrl<T extends Record<string, unknown>> = {
|
|
14
|
+
regex: RegExp;
|
|
15
|
+
query?: DeepLinkUrlQueryParameter<keyof T>[];
|
|
16
|
+
path?: DeepLinkUrlPathParameter<keyof T>[];
|
|
17
|
+
};
|
|
18
|
+
type EmptyObj = {};
|
|
19
|
+
type DeepLink<
|
|
20
|
+
T extends string,
|
|
21
|
+
U extends Record<string, unknown> = EmptyObj,
|
|
22
|
+
V extends Record<string, unknown> = EmptyObj,
|
|
23
|
+
W extends Record<string, unknown> = U
|
|
24
|
+
> = {
|
|
25
|
+
name: T;
|
|
26
|
+
protocolUrls?: DeepLinkUrl<U>[];
|
|
27
|
+
websiteUrls?: DeepLinkUrl<V>[];
|
|
28
|
+
transformProtocolParams?: (params: U) => W | Promise<W | undefined>;
|
|
29
|
+
transformWebsiteParams?: (params: V, url: URL) => W | Promise<W | undefined>;
|
|
30
|
+
arbitaryParameters?: Record<string, boolean | "protocol" | "website" | undefined>;
|
|
31
|
+
toProtocolUrl?: ((params: W) => string) | string;
|
|
32
|
+
toWebsiteUrl?: ((params: W) => string) | string;
|
|
33
|
+
};
|
|
34
|
+
declare function getDeepLinks(getUniverseRootPlaceId: (universeId: number) => Promise<number | null>, getPlaceUniverseId: (placeId: number) => Promise<number | null>, robloxUrl: string): unknown;
|
|
35
|
+
type ExtractParameterType<T> = T extends DeepLink<infer U, infer _V, infer _W, infer X> ? {
|
|
36
|
+
type: U;
|
|
37
|
+
params: X;
|
|
38
|
+
} : never;
|
|
39
|
+
declare class ParsedDeepLink<T extends DeepLink<string>> {
|
|
40
|
+
data: ExtractParameterType<T>;
|
|
41
|
+
private _deepLinkParser;
|
|
42
|
+
private _deepLink;
|
|
43
|
+
constructor(data: ExtractParameterType<T>, _deepLinkParser: DeepLinkParser);
|
|
44
|
+
toProtocolUrl(): string | null;
|
|
45
|
+
toWebsiteUrl(): string | null;
|
|
46
|
+
toAppsFlyerUrl(): string | null;
|
|
47
|
+
}
|
|
48
|
+
type DeepLinkParserUrls = {
|
|
49
|
+
appsFlyerBaseUrl: string;
|
|
50
|
+
robloxPlayerDeepLinkProtocol: string;
|
|
51
|
+
robloxUrl: string;
|
|
52
|
+
robloxApiDomain: string;
|
|
53
|
+
};
|
|
54
|
+
type DeepLinkParserFns = {
|
|
55
|
+
getPlaceUniverseId: (placeId: number) => Promise<number | null>;
|
|
56
|
+
getUniverseRootPlaceId: (placeId: number) => Promise<number | null>;
|
|
57
|
+
};
|
|
58
|
+
type DisallowedParams<T extends DeepLink<string, any, any, any>> = T extends DeepLink<infer K, any, any, infer P> ? Record<K, Array<keyof P>> : never;
|
|
59
|
+
type DeepLinkParserConstructorProps<T extends DeepLink<string, any, any, any>> = {
|
|
60
|
+
urls?: Partial<DeepLinkParserUrls>;
|
|
61
|
+
fns?: Partial<DeepLinkParserFns>;
|
|
62
|
+
fetchFn?: typeof fetch;
|
|
63
|
+
disallowedParams?: DisallowedParams<T>;
|
|
64
|
+
};
|
|
65
|
+
declare class DeepLinkParser<T extends DeepLink<string, any, any, any> = ReturnType<typeof getDeepLinks>[number]> {
|
|
66
|
+
_urls: DeepLinkParserUrls;
|
|
67
|
+
private _fns;
|
|
68
|
+
private _fetchFn;
|
|
69
|
+
private _disallowedParams;
|
|
70
|
+
_deepLinks: T[];
|
|
71
|
+
constructor(data?: DeepLinkParserConstructorProps<T>);
|
|
72
|
+
createDeepLink<U extends T["name"]>(type: U, params: ExtractParameterType<Extract<T, {
|
|
73
|
+
name: U;
|
|
74
|
+
}>>["params"]): ParsedDeepLink<Extract<T, {
|
|
75
|
+
name: U;
|
|
76
|
+
}>> | null;
|
|
77
|
+
parseAppsFlyerLink(url: string): Promise<ParsedDeepLink<T> | null>;
|
|
78
|
+
parseWebsiteLink(url: string): Promise<ParsedDeepLink<T> | null>;
|
|
79
|
+
parseProtocolLink(url: string): Promise<ParsedDeepLink<T> | null>;
|
|
80
|
+
parseLink(url: string): Promise<ParsedDeepLink<T> | null>;
|
|
81
|
+
}
|
|
82
|
+
export { DeepLinkParser as default, DisallowedParams, DeepLinkParserUrls, DeepLinkParserFns, DeepLinkParserConstructorProps };
|