@iann29/rastro 0.4.0 → 0.6.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 (112) hide show
  1. package/README.md +146 -24
  2. package/agent/integration.md +66 -29
  3. package/agent/manifest.json +19 -8
  4. package/agent/manifest.schema.json +28 -9
  5. package/dist/client/federation.d.ts +38 -8
  6. package/dist/client/federation.d.ts.map +1 -1
  7. package/dist/client/federation.js +18 -1
  8. package/dist/client/federation.js.map +1 -1
  9. package/dist/client/identity.d.ts +11 -0
  10. package/dist/client/identity.d.ts.map +1 -0
  11. package/dist/client/identity.js +123 -0
  12. package/dist/client/identity.js.map +1 -0
  13. package/dist/client/index.d.ts +501 -11
  14. package/dist/client/index.d.ts.map +1 -1
  15. package/dist/client/index.js +220 -4
  16. package/dist/client/index.js.map +1 -1
  17. package/dist/component/_generated/api.d.ts +8 -0
  18. package/dist/component/_generated/api.d.ts.map +1 -1
  19. package/dist/component/_generated/api.js.map +1 -1
  20. package/dist/component/_generated/component.d.ts +158 -1
  21. package/dist/component/_generated/component.d.ts.map +1 -1
  22. package/dist/component/constants.d.ts +2 -0
  23. package/dist/component/constants.d.ts.map +1 -1
  24. package/dist/component/constants.js +7 -0
  25. package/dist/component/constants.js.map +1 -1
  26. package/dist/component/coverage.d.ts +1 -0
  27. package/dist/component/coverage.d.ts.map +1 -1
  28. package/dist/component/coverage.js +6 -1
  29. package/dist/component/coverage.js.map +1 -1
  30. package/dist/component/eventStore.d.ts +2 -0
  31. package/dist/component/eventStore.d.ts.map +1 -1
  32. package/dist/component/http.d.ts.map +1 -1
  33. package/dist/component/http.js +51 -1
  34. package/dist/component/http.js.map +1 -1
  35. package/dist/component/ingest.d.ts +2 -0
  36. package/dist/component/ingest.d.ts.map +1 -1
  37. package/dist/component/ingest.js +72 -22
  38. package/dist/component/ingest.js.map +1 -1
  39. package/dist/component/origin.d.ts +70 -0
  40. package/dist/component/origin.d.ts.map +1 -0
  41. package/dist/component/origin.js +230 -0
  42. package/dist/component/origin.js.map +1 -0
  43. package/dist/component/people.d.ts +79 -0
  44. package/dist/component/people.d.ts.map +1 -0
  45. package/dist/component/people.js +249 -0
  46. package/dist/component/people.js.map +1 -0
  47. package/dist/component/platforms.d.ts +33 -0
  48. package/dist/component/platforms.d.ts.map +1 -0
  49. package/dist/component/platforms.js +328 -0
  50. package/dist/component/platforms.js.map +1 -0
  51. package/dist/component/reports.d.ts +35 -74
  52. package/dist/component/reports.d.ts.map +1 -1
  53. package/dist/component/reports.js +59 -14
  54. package/dist/component/reports.js.map +1 -1
  55. package/dist/component/sanitize.d.ts +5 -0
  56. package/dist/component/sanitize.d.ts.map +1 -1
  57. package/dist/component/sanitize.js +33 -1
  58. package/dist/component/sanitize.js.map +1 -1
  59. package/dist/component/schema.d.ts +101 -7
  60. package/dist/component/schema.js +45 -1
  61. package/dist/component/schema.js.map +1 -1
  62. package/dist/component/trackedLinks.d.ts +91 -0
  63. package/dist/component/trackedLinks.d.ts.map +1 -0
  64. package/dist/component/trackedLinks.js +314 -0
  65. package/dist/component/trackedLinks.js.map +1 -0
  66. package/dist/component/useragent.d.ts +6 -0
  67. package/dist/component/useragent.d.ts.map +1 -1
  68. package/dist/component/useragent.js +9 -0
  69. package/dist/component/useragent.js.map +1 -1
  70. package/dist/component/validators.d.ts +101 -11
  71. package/dist/component/validators.d.ts.map +1 -1
  72. package/dist/component/validators.js +62 -1
  73. package/dist/component/validators.js.map +1 -1
  74. package/dist/component/visitors.d.ts +38 -2
  75. package/dist/component/visitors.d.ts.map +1 -1
  76. package/dist/component/visitors.js +162 -42
  77. package/dist/component/visitors.js.map +1 -1
  78. package/dist/react/index.d.ts +9 -5
  79. package/dist/react/index.d.ts.map +1 -1
  80. package/dist/react/index.js +36 -5
  81. package/dist/react/index.js.map +1 -1
  82. package/dist/tracker/generated.d.ts +6 -6
  83. package/dist/tracker/generated.d.ts.map +1 -1
  84. package/dist/tracker/generated.js +6 -6
  85. package/dist/tracker/generated.js.map +1 -1
  86. package/dist/tracker/tracker.d.ts +3 -1
  87. package/dist/tracker/tracker.d.ts.map +1 -1
  88. package/dist/tracker/tracker.js +56 -5
  89. package/dist/tracker/tracker.js.map +1 -1
  90. package/dist/tracker.min.js +1 -1
  91. package/docs/federation.md +24 -0
  92. package/docs/identity.md +307 -0
  93. package/docs/upgrading.md +190 -19
  94. package/llms.txt +11 -2
  95. package/package.json +5 -3
  96. package/src/component/_generated/api.ts +8 -0
  97. package/src/component/_generated/component.ts +251 -1
  98. package/src/component/constants.ts +7 -0
  99. package/src/component/coverage.ts +7 -1
  100. package/src/component/http.ts +56 -1
  101. package/src/component/ingest.ts +100 -28
  102. package/src/component/origin.ts +273 -0
  103. package/src/component/people.ts +321 -0
  104. package/src/component/platforms.ts +359 -0
  105. package/src/component/reports.ts +84 -13
  106. package/src/component/sanitize.ts +39 -1
  107. package/src/component/schema.ts +53 -0
  108. package/src/component/trackedLinks.ts +384 -0
  109. package/src/component/useragent.ts +11 -0
  110. package/src/component/validators.ts +120 -0
  111. package/src/component/visitors.ts +232 -55
  112. package/src/tracker/generated.ts +6 -6
@@ -0,0 +1,91 @@
1
+ import { type Infer } from "convex/values";
2
+ declare const redirectValidator: import("convex/values").VObject<{
3
+ campaign?: string | undefined;
4
+ channel: "affiliate" | "display" | "email" | "messaging" | "offline" | "organic_social" | "paid_social" | "referral";
5
+ destination: string;
6
+ platform: string;
7
+ slug: string;
8
+ }, {
9
+ slug: import("convex/values").VString<string, "required">;
10
+ destination: import("convex/values").VString<string, "required">;
11
+ platform: import("convex/values").VString<string, "required">;
12
+ channel: import("convex/values").VUnion<"affiliate" | "display" | "email" | "messaging" | "offline" | "organic_social" | "paid_social" | "referral", [import("convex/values").VLiteral<"organic_social", "required">, import("convex/values").VLiteral<"paid_social", "required">, import("convex/values").VLiteral<"messaging", "required">, import("convex/values").VLiteral<"email", "required">, import("convex/values").VLiteral<"affiliate", "required">, import("convex/values").VLiteral<"display", "required">, import("convex/values").VLiteral<"referral", "required">, import("convex/values").VLiteral<"offline", "required">], "required", never>;
13
+ campaign: import("convex/values").VString<string | undefined, "optional">;
14
+ }, "required", "campaign" | "channel" | "destination" | "platform" | "slug">;
15
+ export declare function isTrackedLinkSlug(value: string): boolean;
16
+ /**
17
+ * Where a click lands: the destination with the link's utm_* appended. A key
18
+ * the destination already carries wins, and its own query keeps its exact
19
+ * encoding because the tags are appended as text.
20
+ */
21
+ export declare function trackedLinkLocation(link: Infer<typeof redirectValidator>): string;
22
+ export declare const create: import("convex/server").RegisteredMutation<"public", {
23
+ campaign?: string | undefined;
24
+ channel: "affiliate" | "display" | "email" | "messaging" | "offline" | "organic_social" | "paid_social" | "referral";
25
+ createdBy: string;
26
+ destination: string;
27
+ platform: string;
28
+ siteId: import("convex/values").GenericId<"sites">;
29
+ slug: string;
30
+ }, Promise<import("convex/values").GenericId<"trackedLinks">>>;
31
+ /** Everything but the slug, which every link already printed carries. */
32
+ export declare const update: import("convex/server").RegisteredMutation<"public", {
33
+ campaign?: string | null | undefined;
34
+ channel?: "affiliate" | "display" | "email" | "messaging" | "offline" | "organic_social" | "paid_social" | "referral" | undefined;
35
+ destination?: string | undefined;
36
+ disabled?: boolean | undefined;
37
+ linkId: import("convex/values").GenericId<"trackedLinks">;
38
+ platform?: string | undefined;
39
+ siteId: import("convex/values").GenericId<"sites">;
40
+ }, Promise<null>>;
41
+ export declare const remove: import("convex/server").RegisteredMutation<"public", {
42
+ linkId: import("convex/values").GenericId<"trackedLinks">;
43
+ siteId: import("convex/values").GenericId<"sites">;
44
+ }, Promise<null>>;
45
+ /**
46
+ * The site's links, newest first, with their clicks and bot hits: all time,
47
+ * and over the 30 UTC days ending on the day of `now`. The caller passes the
48
+ * clock so the subscription does not go stale.
49
+ */
50
+ export declare const list: import("convex/server").RegisteredQuery<"public", {
51
+ now: number;
52
+ siteId: import("convex/values").GenericId<"sites">;
53
+ }, Promise<{
54
+ _creationTime: number;
55
+ _id: import("convex/values").GenericId<"trackedLinks">;
56
+ clicks: number;
57
+ bots: number;
58
+ clicksLast30Days: number;
59
+ botsLast30Days: number;
60
+ campaign?: string | undefined;
61
+ channel: "affiliate" | "display" | "email" | "messaging" | "offline" | "organic_social" | "paid_social" | "referral";
62
+ createdAt: number;
63
+ createdBy: string;
64
+ destination: string;
65
+ disabledAt?: number | undefined;
66
+ platform: string;
67
+ siteId: import("convex/values").GenericId<"sites">;
68
+ slug: string;
69
+ }[]>>;
70
+ /**
71
+ * Counts one click on a live link and returns where it goes, or null for an
72
+ * unknown or disabled slug. Bots are counted apart and never as clicks. The
73
+ * destination is checked against the site's domains again, so a domain the
74
+ * site has since dropped stops redirecting.
75
+ */
76
+ export declare const recordClick: import("convex/server").RegisteredMutation<"internal", {
77
+ bot: boolean;
78
+ slug: string;
79
+ }, Promise<{
80
+ slug: string;
81
+ destination: string;
82
+ platform: string;
83
+ channel: "affiliate" | "display" | "email" | "messaging" | "offline" | "organic_social" | "paid_social" | "referral";
84
+ campaign?: string | undefined;
85
+ } | null>>;
86
+ /** Deletes a removed link's counters a batch at a time. */
87
+ export declare const purgeClicks: import("convex/server").RegisteredMutation<"internal", {
88
+ linkId: import("convex/values").GenericId<"trackedLinks">;
89
+ }, Promise<null>>;
90
+ export {};
91
+ //# sourceMappingURL=trackedLinks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trackedLinks.d.ts","sourceRoot":"","sources":["../../src/component/trackedLinks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAgC9C,QAAA,MAAM,iBAAiB;;;;;;;;;;;;4EAMtB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,KAAK,CAAC,OAAO,iBAAiB,CAAC,GACpC,MAAM,CAaR;AA6DD,eAAO,MAAM,MAAM;;;;;;;;8DAmDjB,CAAC;AAEH,yEAAyE;AACzE,eAAO,MAAM,MAAM;;;;;;;;iBA2CjB,CAAC;AAEH,eAAO,MAAM,MAAM;;;iBAcjB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;KAgEf,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,WAAW;;;;;;;;;UA+CtB,CAAC;AAEH,2DAA2D;AAC3D,eAAO,MAAM,WAAW;;iBAgBtB,CAAC"}
@@ -0,0 +1,314 @@
1
+ import { v } from "convex/values";
2
+ import { internal } from "./_generated/api.js";
3
+ import { internalMutation, mutation, query } from "./_generated/server.js";
4
+ import { DAY_MS, MAX_TRACKED_LINKS_PER_SITE, TRACKED_LINK_CLICK_SHARDS, } from "./constants.js";
5
+ import { fail } from "./errors.js";
6
+ import { cleanString, originAllowed, sanitizeOpaqueId } from "./sanitize.js";
7
+ import { trackedLinkChannelValidator, trackedLinkFieldsValidator, } from "./validators.js";
8
+ const SLUG = /^[a-z0-9][a-z0-9-]{1,30}[a-z0-9]$/;
9
+ const PLATFORM = /^[a-z0-9_]{2,24}$/;
10
+ const MAX_DESTINATION_LENGTH = 2048;
11
+ const MAX_CAMPAIGN_LENGTH = 64;
12
+ const RECENT_DAYS = 30;
13
+ // Each shard's all-time counter sits beside the daily ones under this day, so
14
+ // a link's total is TRACKED_LINK_CLICK_SHARDS rows however long it has lived.
15
+ const ALL_TIME = 0;
16
+ const PURGE_BATCH = 500;
17
+ const trackedLinkDocumentValidator = trackedLinkFieldsValidator.extend({
18
+ _id: v.id("trackedLinks"),
19
+ _creationTime: v.number(),
20
+ });
21
+ const redirectValidator = trackedLinkFieldsValidator.pick("slug", "destination", "platform", "channel", "campaign");
22
+ export function isTrackedLinkSlug(value) {
23
+ return SLUG.test(value);
24
+ }
25
+ /**
26
+ * Where a click lands: the destination with the link's utm_* appended. A key
27
+ * the destination already carries wins, and its own query keeps its exact
28
+ * encoding because the tags are appended as text.
29
+ */
30
+ export function trackedLinkLocation(link) {
31
+ const url = new URL(link.destination);
32
+ const utm = [
33
+ ["utm_source", link.platform],
34
+ ["utm_medium", link.channel],
35
+ ["utm_campaign", link.campaign ?? link.slug],
36
+ ["utm_content", link.slug],
37
+ ];
38
+ const tags = new URLSearchParams(utm.filter(([key]) => !url.searchParams.has(key))).toString();
39
+ if (tags)
40
+ url.search = url.search ? `${url.search}&${tags}` : `?${tags}`;
41
+ return url.href;
42
+ }
43
+ function sanitizeLinkSlug(value) {
44
+ const slug = value.trim().toLowerCase();
45
+ if (!isTrackedLinkSlug(slug)) {
46
+ fail("INVALID_ARGUMENT", "slug must be 3 to 32 lowercase letters, digits or hyphens, starting and ending with a letter or digit");
47
+ }
48
+ return slug;
49
+ }
50
+ function sanitizePlatform(value) {
51
+ const platform = value.trim().toLowerCase();
52
+ if (!PLATFORM.test(platform)) {
53
+ fail("INVALID_ARGUMENT", "platform must be 2 to 24 lowercase letters, digits or underscores");
54
+ }
55
+ return platform;
56
+ }
57
+ function sanitizeCampaign(value) {
58
+ return value === undefined
59
+ ? undefined
60
+ : cleanString(value, MAX_CAMPAIGN_LENGTH) || undefined;
61
+ }
62
+ // No open redirect: the destination is an absolute http(s) URL on one of the
63
+ // site's own domains, the same rule the ingestion origin check applies.
64
+ function sanitizeDestination(value, domains) {
65
+ let url;
66
+ try {
67
+ if (value.length <= MAX_DESTINATION_LENGTH) {
68
+ url = new URL(cleanString(value, MAX_DESTINATION_LENGTH));
69
+ }
70
+ }
71
+ catch {
72
+ url = undefined;
73
+ }
74
+ if (!url ||
75
+ (url.protocol !== "http:" && url.protocol !== "https:") ||
76
+ url.username ||
77
+ url.password) {
78
+ fail("INVALID_ARGUMENT", "destination must be an absolute http(s) URL without credentials");
79
+ }
80
+ if (!originAllowed(url.href, domains)) {
81
+ fail("INVALID_ARGUMENT", "destination must be on one of the site's domains");
82
+ }
83
+ return url.href;
84
+ }
85
+ export const create = mutation({
86
+ args: {
87
+ siteId: v.id("sites"),
88
+ slug: v.string(),
89
+ destination: v.string(),
90
+ platform: v.string(),
91
+ channel: trackedLinkChannelValidator,
92
+ campaign: v.optional(v.string()),
93
+ createdBy: v.string(),
94
+ },
95
+ returns: v.id("trackedLinks"),
96
+ handler: async (ctx, args) => {
97
+ const site = await ctx.db.get("sites", args.siteId);
98
+ if (!site)
99
+ fail("NOT_FOUND", "site not found");
100
+ const slug = sanitizeLinkSlug(args.slug);
101
+ const destination = sanitizeDestination(args.destination, site.domains);
102
+ const platform = sanitizePlatform(args.platform);
103
+ let createdBy;
104
+ try {
105
+ createdBy = sanitizeOpaqueId(args.createdBy, "createdBy");
106
+ }
107
+ catch (error) {
108
+ fail("INVALID_ARGUMENT", error instanceof Error ? error.message : "invalid createdBy");
109
+ }
110
+ const taken = await ctx.db
111
+ .query("trackedLinks")
112
+ .withIndex("by_slug", (range) => range.eq("slug", slug))
113
+ .unique();
114
+ if (taken)
115
+ fail("CONFLICT", "another tracked link already uses this slug");
116
+ const links = await ctx.db
117
+ .query("trackedLinks")
118
+ .withIndex("by_siteId", (range) => range.eq("siteId", args.siteId))
119
+ .take(MAX_TRACKED_LINKS_PER_SITE);
120
+ if (links.length >= MAX_TRACKED_LINKS_PER_SITE) {
121
+ fail("LIMIT_EXCEEDED", "tracked link limit reached", {
122
+ limit: MAX_TRACKED_LINKS_PER_SITE,
123
+ });
124
+ }
125
+ return await ctx.db.insert("trackedLinks", {
126
+ siteId: args.siteId,
127
+ slug,
128
+ destination,
129
+ platform,
130
+ channel: args.channel,
131
+ campaign: sanitizeCampaign(args.campaign),
132
+ createdAt: Date.now(),
133
+ createdBy,
134
+ });
135
+ },
136
+ });
137
+ /** Everything but the slug, which every link already printed carries. */
138
+ export const update = mutation({
139
+ args: {
140
+ siteId: v.id("sites"),
141
+ linkId: v.id("trackedLinks"),
142
+ destination: v.optional(v.string()),
143
+ platform: v.optional(v.string()),
144
+ channel: v.optional(trackedLinkChannelValidator),
145
+ campaign: v.optional(v.union(v.string(), v.null())),
146
+ disabled: v.optional(v.boolean()),
147
+ },
148
+ returns: v.null(),
149
+ handler: async (ctx, args) => {
150
+ const link = await ctx.db.get("trackedLinks", args.linkId);
151
+ if (!link || link.siteId !== args.siteId) {
152
+ fail("NOT_FOUND", "tracked link not found");
153
+ }
154
+ const patch = {};
155
+ if (args.destination !== undefined) {
156
+ const site = await ctx.db.get("sites", args.siteId);
157
+ if (!site)
158
+ fail("NOT_FOUND", "site not found");
159
+ patch.destination = sanitizeDestination(args.destination, site.domains);
160
+ }
161
+ if (args.platform !== undefined) {
162
+ patch.platform = sanitizePlatform(args.platform);
163
+ }
164
+ if (args.channel !== undefined)
165
+ patch.channel = args.channel;
166
+ if (args.campaign !== undefined) {
167
+ patch.campaign = sanitizeCampaign(args.campaign ?? undefined);
168
+ }
169
+ if (args.disabled !== undefined) {
170
+ patch.disabledAt = args.disabled
171
+ ? (link.disabledAt ?? Date.now())
172
+ : undefined;
173
+ }
174
+ await ctx.db.patch("trackedLinks", args.linkId, patch);
175
+ return null;
176
+ },
177
+ });
178
+ export const remove = mutation({
179
+ args: { siteId: v.id("sites"), linkId: v.id("trackedLinks") },
180
+ returns: v.null(),
181
+ handler: async (ctx, args) => {
182
+ const link = await ctx.db.get("trackedLinks", args.linkId);
183
+ if (!link || link.siteId !== args.siteId) {
184
+ fail("NOT_FOUND", "tracked link not found");
185
+ }
186
+ await ctx.db.delete("trackedLinks", args.linkId);
187
+ await ctx.scheduler.runAfter(0, internal.trackedLinks.purgeClicks, {
188
+ linkId: args.linkId,
189
+ });
190
+ return null;
191
+ },
192
+ });
193
+ /**
194
+ * The site's links, newest first, with their clicks and bot hits: all time,
195
+ * and over the 30 UTC days ending on the day of `now`. The caller passes the
196
+ * clock so the subscription does not go stale.
197
+ */
198
+ export const list = query({
199
+ args: { siteId: v.id("sites"), now: v.number() },
200
+ returns: v.array(trackedLinkDocumentValidator.extend({
201
+ clicks: v.number(),
202
+ bots: v.number(),
203
+ clicksLast30Days: v.number(),
204
+ botsLast30Days: v.number(),
205
+ })),
206
+ handler: async (ctx, args) => {
207
+ if (!Number.isSafeInteger(args.now) || args.now < RECENT_DAYS * DAY_MS) {
208
+ fail("INVALID_ARGUMENT", "now must be a Unix time in milliseconds");
209
+ }
210
+ const since = Math.floor(args.now / DAY_MS) * DAY_MS - (RECENT_DAYS - 1) * DAY_MS;
211
+ const links = await ctx.db
212
+ .query("trackedLinks")
213
+ .withIndex("by_siteId", (range) => range.eq("siteId", args.siteId))
214
+ .order("desc")
215
+ .take(MAX_TRACKED_LINKS_PER_SITE);
216
+ const sum = (rows) => rows.reduce((total, row) => ({
217
+ clicks: total.clicks + row.clicks,
218
+ bots: total.bots + row.bots,
219
+ }), { clicks: 0, bots: 0 });
220
+ // Up to 4 + 120 counter rows per link, so a full site of 200 links whose
221
+ // every link fills every shard every day reads about 24,800 rows, inside
222
+ // the 32,000 documents a query may read. Raising either cap needs a
223
+ // finished day's shards folded into one row first.
224
+ return await Promise.all(links.map(async (link) => {
225
+ const total = sum(await ctx.db
226
+ .query("trackedLinkClicks")
227
+ .withIndex("by_linkId_and_dayStart_and_shard", (range) => range.eq("linkId", link._id).eq("dayStart", ALL_TIME))
228
+ .take(TRACKED_LINK_CLICK_SHARDS));
229
+ const recent = sum(await ctx.db
230
+ .query("trackedLinkClicks")
231
+ .withIndex("by_linkId_and_dayStart_and_shard", (range) => range
232
+ .eq("linkId", link._id)
233
+ .gte("dayStart", since)
234
+ .lt("dayStart", since + RECENT_DAYS * DAY_MS))
235
+ .take(RECENT_DAYS * TRACKED_LINK_CLICK_SHARDS));
236
+ return {
237
+ ...link,
238
+ clicks: total.clicks,
239
+ bots: total.bots,
240
+ clicksLast30Days: recent.clicks,
241
+ botsLast30Days: recent.bots,
242
+ };
243
+ }));
244
+ },
245
+ });
246
+ /**
247
+ * Counts one click on a live link and returns where it goes, or null for an
248
+ * unknown or disabled slug. Bots are counted apart and never as clicks. The
249
+ * destination is checked against the site's domains again, so a domain the
250
+ * site has since dropped stops redirecting.
251
+ */
252
+ export const recordClick = internalMutation({
253
+ args: { slug: v.string(), bot: v.boolean() },
254
+ returns: v.union(redirectValidator, v.null()),
255
+ handler: async (ctx, args) => {
256
+ const link = await ctx.db
257
+ .query("trackedLinks")
258
+ .withIndex("by_slug", (range) => range.eq("slug", args.slug))
259
+ .unique();
260
+ if (!link || link.disabledAt !== undefined)
261
+ return null;
262
+ const site = await ctx.db.get("sites", link.siteId);
263
+ if (!site || !originAllowed(link.destination, site.domains))
264
+ return null;
265
+ const now = Date.now();
266
+ const shard = Math.floor(Math.random() * TRACKED_LINK_CLICK_SHARDS);
267
+ for (const dayStart of [Math.floor(now / DAY_MS) * DAY_MS, ALL_TIME]) {
268
+ const row = await ctx.db
269
+ .query("trackedLinkClicks")
270
+ .withIndex("by_linkId_and_dayStart_and_shard", (range) => range
271
+ .eq("linkId", link._id)
272
+ .eq("dayStart", dayStart)
273
+ .eq("shard", shard))
274
+ .unique();
275
+ if (row) {
276
+ await ctx.db.patch("trackedLinkClicks", row._id, args.bot ? { bots: row.bots + 1 } : { clicks: row.clicks + 1 });
277
+ }
278
+ else {
279
+ await ctx.db.insert("trackedLinkClicks", {
280
+ linkId: link._id,
281
+ dayStart,
282
+ shard,
283
+ clicks: args.bot ? 0 : 1,
284
+ bots: args.bot ? 1 : 0,
285
+ });
286
+ }
287
+ }
288
+ return {
289
+ slug: link.slug,
290
+ destination: link.destination,
291
+ platform: link.platform,
292
+ channel: link.channel,
293
+ ...(link.campaign === undefined ? {} : { campaign: link.campaign }),
294
+ };
295
+ },
296
+ });
297
+ /** Deletes a removed link's counters a batch at a time. */
298
+ export const purgeClicks = internalMutation({
299
+ args: { linkId: v.id("trackedLinks") },
300
+ returns: v.null(),
301
+ handler: async (ctx, args) => {
302
+ const rows = await ctx.db
303
+ .query("trackedLinkClicks")
304
+ .withIndex("by_linkId_and_dayStart_and_shard", (range) => range.eq("linkId", args.linkId))
305
+ .take(PURGE_BATCH);
306
+ for (const row of rows)
307
+ await ctx.db.delete("trackedLinkClicks", row._id);
308
+ if (rows.length === PURGE_BATCH) {
309
+ await ctx.scheduler.runAfter(0, internal.trackedLinks.purgeClicks, args);
310
+ }
311
+ return null;
312
+ },
313
+ });
314
+ //# sourceMappingURL=trackedLinks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trackedLinks.js","sourceRoot":"","sources":["../../src/component/trackedLinks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAc,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EACL,MAAM,EACN,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC;AAEzB,MAAM,IAAI,GAAG,mCAAmC,CAAC;AACjD,MAAM,QAAQ,GAAG,mBAAmB,CAAC;AACrC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AACpC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAC/B,MAAM,WAAW,GAAG,EAAE,CAAC;AACvB,8EAA8E;AAC9E,8EAA8E;AAC9E,MAAM,QAAQ,GAAG,CAAC,CAAC;AACnB,MAAM,WAAW,GAAG,GAAG,CAAC;AAIxB,MAAM,4BAA4B,GAAG,0BAA0B,CAAC,MAAM,CAAC;IACrE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC;IACzB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;CAC1B,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,0BAA0B,CAAC,IAAI,CACvD,MAAM,EACN,aAAa,EACb,UAAU,EACV,SAAS,EACT,UAAU,CACX,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAqC;IAErC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtC,MAAM,GAAG,GAA4B;QACnC,CAAC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC;QAC7B,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC;QAC5B,CAAC,cAAc,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC;QAC5C,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC;KAC3B,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,eAAe,CAC9B,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAClD,CAAC,QAAQ,EAAE,CAAC;IACb,IAAI,IAAI;QAAE,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IACzE,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,IAAI,CACF,kBAAkB,EAClB,uGAAuG,CACxG,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa;IACrC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,IAAI,CACF,kBAAkB,EAClB,mEAAmE,CACpE,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAyB;IACjD,OAAO,KAAK,KAAK,SAAS;QACxB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,mBAAmB,CAAC,IAAI,SAAS,CAAC;AAC3D,CAAC;AAED,6EAA6E;AAC7E,wEAAwE;AACxE,SAAS,mBAAmB,CAAC,KAAa,EAAE,OAAiB;IAC3D,IAAI,GAAoB,CAAC;IACzB,IAAI,CAAC;QACH,IAAI,KAAK,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC;YAC3C,GAAG,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,KAAK,EAAE,sBAAsB,CAAC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,GAAG,SAAS,CAAC;IAClB,CAAC;IACD,IACE,CAAC,GAAG;QACJ,CAAC,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;QACvD,GAAG,CAAC,QAAQ;QACZ,GAAG,CAAC,QAAQ,EACZ,CAAC;QACD,IAAI,CACF,kBAAkB,EAClB,iEAAiE,CAClE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;QACtC,IAAI,CACF,kBAAkB,EAClB,kDAAkD,CACnD,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,QAAQ,CAAC;IAC7B,IAAI,EAAE;QACJ,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;QACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;QACvB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;QACpB,OAAO,EAAE,2BAA2B;QACpC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;KACtB;IACD,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC;IAC7B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC3B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACxE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,SAAiB,CAAC;QACtB,IAAI,CAAC;YACH,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC5D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CACF,kBAAkB,EAClB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAC7D,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,EAAE;aACvB,KAAK,CAAC,cAAc,CAAC;aACrB,SAAS,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;aACvD,MAAM,EAAE,CAAC;QACZ,IAAI,KAAK;YAAE,IAAI,CAAC,UAAU,EAAE,6CAA6C,CAAC,CAAC;QAC3E,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,EAAE;aACvB,KAAK,CAAC,cAAc,CAAC;aACrB,SAAS,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;aAClE,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,MAAM,IAAI,0BAA0B,EAAE,CAAC;YAC/C,IAAI,CAAC,gBAAgB,EAAE,4BAA4B,EAAE;gBACnD,KAAK,EAAE,0BAA0B;aAClC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE;YACzC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,IAAI;YACJ,WAAW;YACX,QAAQ;YACR,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC;YACzC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,SAAS;SACV,CAAC,CAAC;IACL,CAAC;CACF,CAAC,CAAC;AAEH,yEAAyE;AACzE,MAAM,CAAC,MAAM,MAAM,GAAG,QAAQ,CAAC;IAC7B,IAAI,EAAE;QACJ,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;QACrB,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC;QAC5B,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACnC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAChC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QAChD,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACnD,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;KAClC;IACD,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE;IACjB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC3B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3D,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YACzC,IAAI,CAAC,WAAW,EAAE,wBAAwB,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,KAAK,GAMP,EAAE,CAAC;QACP,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACpD,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;YAC/C,KAAK,CAAC,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1E,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,KAAK,CAAC,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7D,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,KAAK,CAAC,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ;gBAC9B,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACjC,CAAC,CAAC,SAAS,CAAC;QAChB,CAAC;QACD,MAAM,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG,QAAQ,CAAC;IAC7B,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE;IAC7D,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE;IACjB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAiB,EAAE;QAC1C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3D,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YACzC,IAAI,CAAC,WAAW,EAAE,wBAAwB,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACjD,MAAM,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,YAAY,CAAC,WAAW,EAAE;YACjE,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,KAAK,CAAC;IACxB,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE;IAChD,OAAO,EAAE,CAAC,CAAC,KAAK,CACd,4BAA4B,CAAC,MAAM,CAAC;QAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;QAC5B,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;KAC3B,CAAC,CACH;IACD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC3B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,WAAW,GAAG,MAAM,EAAE,CAAC;YACvE,IAAI,CAAC,kBAAkB,EAAE,yCAAyC,CAAC,CAAC;QACtE,CAAC;QACD,MAAM,KAAK,GACT,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;QACtE,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,EAAE;aACvB,KAAK,CAAC,cAAc,CAAC;aACrB,SAAS,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;aAClE,KAAK,CAAC,MAAM,CAAC;aACb,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,CAAC,IAA6C,EAAE,EAAE,CAC5D,IAAI,CAAC,MAAM,CACT,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACf,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM;YACjC,IAAI,EAAE,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI;SAC5B,CAAC,EACF,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CACvB,CAAC;QACJ,yEAAyE;QACzE,yEAAyE;QACzE,oEAAoE;QACpE,mDAAmD;QACnD,OAAO,MAAM,OAAO,CAAC,GAAG,CACtB,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YACvB,MAAM,KAAK,GAAG,GAAG,CACf,MAAM,GAAG,CAAC,EAAE;iBACT,KAAK,CAAC,mBAAmB,CAAC;iBAC1B,SAAS,CAAC,kCAAkC,EAAE,CAAC,KAAK,EAAE,EAAE,CACvD,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,CACtD;iBACA,IAAI,CAAC,yBAAyB,CAAC,CACnC,CAAC;YACF,MAAM,MAAM,GAAG,GAAG,CAChB,MAAM,GAAG,CAAC,EAAE;iBACT,KAAK,CAAC,mBAAmB,CAAC;iBAC1B,SAAS,CAAC,kCAAkC,EAAE,CAAC,KAAK,EAAE,EAAE,CACvD,KAAK;iBACF,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC;iBACtB,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC;iBACtB,EAAE,CAAC,UAAU,EAAE,KAAK,GAAG,WAAW,GAAG,MAAM,CAAC,CAChD;iBACA,IAAI,CAAC,WAAW,GAAG,yBAAyB,CAAC,CACjD,CAAC;YACF,OAAO;gBACL,GAAG,IAAI;gBACP,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,gBAAgB,EAAE,MAAM,CAAC,MAAM;gBAC/B,cAAc,EAAE,MAAM,CAAC,IAAI;aAC5B,CAAC;QACJ,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,CAAC;IAC1C,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE;IAC5C,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7C,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC3B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE;aACtB,KAAK,CAAC,cAAc,CAAC;aACrB,SAAS,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;aAC5D,MAAM,EAAE,CAAC;QACZ,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACxD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QACzE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,yBAAyB,CAAC,CAAC;QACpE,KAAK,MAAM,QAAQ,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;YACrE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,EAAE;iBACrB,KAAK,CAAC,mBAAmB,CAAC;iBAC1B,SAAS,CAAC,kCAAkC,EAAE,CAAC,KAAK,EAAE,EAAE,CACvD,KAAK;iBACF,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC;iBACtB,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC;iBACxB,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CACtB;iBACA,MAAM,EAAE,CAAC;YACZ,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,GAAG,CAAC,EAAE,CAAC,KAAK,CAChB,mBAAmB,EACnB,GAAG,CAAC,GAAG,EACP,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAC/D,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,mBAAmB,EAAE;oBACvC,MAAM,EAAE,IAAI,CAAC,GAAG;oBAChB,QAAQ;oBACR,KAAK;oBACL,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACxB,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBACvB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;SACpE,CAAC;IACJ,CAAC;CACF,CAAC,CAAC;AAEH,2DAA2D;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,CAAC;IAC1C,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE;IACtC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE;IACjB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAiB,EAAE;QAC1C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE;aACtB,KAAK,CAAC,mBAAmB,CAAC;aAC1B,SAAS,CAAC,kCAAkC,EAAE,CAAC,KAAK,EAAE,EAAE,CACvD,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAChC;aACA,IAAI,CAAC,WAAW,CAAC,CAAC;QACrB,KAAK,MAAM,GAAG,IAAI,IAAI;YAAE,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,mBAAmB,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1E,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAChC,MAAM,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,YAAY,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC,CAAC"}
@@ -5,5 +5,11 @@ export type ClientClassification = {
5
5
  };
6
6
  export declare function classifyClient(userAgent: string, headers: Headers): ClientClassification;
7
7
  export declare function classifyUserAgent(userAgent: string): ClientClassification;
8
+ /**
9
+ * The platform whose in-app browser sent the request (Instagram, Facebook,
10
+ * TikTok…), from the marker each app appends to the User-Agent. The system
11
+ * browser a messaging app hands a link to carries none.
12
+ */
13
+ export declare function inAppPlatform(userAgent: string): string | undefined;
8
14
  export declare function isKnownBot(userAgent: string): boolean;
9
15
  //# sourceMappingURL=useragent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useragent.d.ts","sourceRoot":"","sources":["../../src/component/useragent.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AA2EF,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACf,oBAAoB,CAUtB;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,CAMzE;AAoED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAErD"}
1
+ {"version":3,"file":"useragent.d.ts","sourceRoot":"","sources":["../../src/component/useragent.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AA2EF,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACf,oBAAoB,CAUtB;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,CAMzE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEnE;AAoED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAErD"}
@@ -1,3 +1,4 @@
1
+ import { PLATFORMS } from "./platforms.js";
1
2
  // The tracker never reports the client: everything here is derived from headers
2
3
  // the browser sets itself. Chromium sends the low-entropy `Sec-CH-UA` hints on
3
4
  // cross-origin requests without an `Accept-CH` opt-in, which is the only way to
@@ -80,6 +81,14 @@ export function classifyUserAgent(userAgent) {
80
81
  device: matchAgent(AGENT_DEVICES, userAgent) ?? "desktop",
81
82
  };
82
83
  }
84
+ /**
85
+ * The platform whose in-app browser sent the request (Instagram, Facebook,
86
+ * TikTok…), from the marker each app appends to the User-Agent. The system
87
+ * browser a messaging app hands a link to carries none.
88
+ */
89
+ export function inAppPlatform(userAgent) {
90
+ return PLATFORMS.find((row) => row.agent?.test(userAgent))?.id;
91
+ }
83
92
  function matchAgent(table, userAgent) {
84
93
  for (const [pattern, value] of table) {
85
94
  if (pattern.test(userAgent))
@@ -1 +1 @@
1
- {"version":3,"file":"useragent.js","sourceRoot":"","sources":["../../src/component/useragent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useragent.js","sourceRoot":"","sources":["../../src/component/useragent.ts"],"names":[],"mappings":"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"}