@bash-app/bash-common 30.347.0 → 30.355.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/dist/__tests__/eventTimezoneIana.test.d.ts +2 -0
- package/dist/__tests__/eventTimezoneIana.test.d.ts.map +1 -0
- package/dist/__tests__/eventTimezoneIana.test.js +282 -0
- package/dist/__tests__/eventTimezoneIana.test.js.map +1 -0
- package/dist/extendedSchemas.d.ts +177 -0
- package/dist/extendedSchemas.d.ts.map +1 -1
- package/dist/extendedSchemas.js +3 -0
- package/dist/extendedSchemas.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/__tests__/moodTrackUtils.test.d.ts +2 -0
- package/dist/utils/__tests__/moodTrackUtils.test.d.ts.map +1 -0
- package/dist/utils/__tests__/moodTrackUtils.test.js +25 -0
- package/dist/utils/__tests__/moodTrackUtils.test.js.map +1 -0
- package/dist/utils/blog/blogCommentDbUtils.d.ts +4 -0
- package/dist/utils/blog/blogCommentDbUtils.d.ts.map +1 -1
- package/dist/utils/eventTimezoneIana.d.ts.map +1 -1
- package/dist/utils/eventTimezoneIana.js +15 -2
- package/dist/utils/eventTimezoneIana.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/luxonUtils.d.ts +7 -7
- package/dist/utils/luxonUtils.d.ts.map +1 -1
- package/dist/utils/moodTrackUtils.d.ts +23 -0
- package/dist/utils/moodTrackUtils.d.ts.map +1 -0
- package/dist/utils/moodTrackUtils.js +171 -0
- package/dist/utils/moodTrackUtils.js.map +1 -0
- package/package.json +1 -1
- package/prisma/schema.prisma +26 -0
- package/src/__tests__/eventTimezoneIana.test.ts +387 -0
- package/src/extendedSchemas.ts +3 -0
- package/src/index.ts +1 -0
- package/src/utils/__tests__/moodTrackUtils.test.ts +46 -0
- package/src/utils/eventTimezoneIana.ts +14 -3
- package/src/utils/index.ts +1 -0
- package/src/utils/moodTrackUtils.ts +190 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"luxonUtils.d.ts","sourceRoot":"","sources":["../../src/utils/luxonUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EACL,YAAY,EAIb,MAAM,2BAA2B,CAAC;AAInC,eAAO,MAAM,8BAA8B,QAAQ,CAAC;AACpD,eAAO,MAAM,yBAAyB,QAAQ,CAAC;AAC/C,eAAO,MAAM,8BAA8B,QAAQ,CAAC;AACpD,eAAO,MAAM,uCAAuC,aAAa,CAAC;AAGlE,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAC9C,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAEhD,eAAO,MAAM,eAAe,OAAO,CAAC;AAEpC,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AACnD,eAAO,MAAM,0BAA0B,uBAAuB,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,QAAQ,CAAC;IAChB,GAAG,EAAE,QAAQ,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC;IACpC,GAAG,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC;CACnC;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,YAAY,gBAQlE;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,GAAG,YAAY,6CAQnE;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,SAAS,GAAG,YAAY,EACnC,IAAI,GAAE,MAAU,EAChB,MAAM,GAAE,MAAU,EAClB,mBAAmB,CAAC,EAAE,MAAM,EAC5B,mBAAmB,CAAC,EAAE,MAAM,GAC3B,QAAQ,CAqBV;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,mBAAmB,CAAC,EAAE,MAAM,EAC5B,mBAAmB,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"luxonUtils.d.ts","sourceRoot":"","sources":["../../src/utils/luxonUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bash mood track — optional soundtrack URL on a bash.
|
|
3
|
+
* Preferred: YouTube Music. Also: Spotify, Apple Music, SoundCloud.
|
|
4
|
+
* Guests tap to play; never autoplay.
|
|
5
|
+
*/
|
|
6
|
+
export type MoodTrackProvider = "youtubeMusic" | "spotify" | "appleMusic" | "soundcloud";
|
|
7
|
+
export type MoodTrackEmbed = {
|
|
8
|
+
provider: MoodTrackProvider;
|
|
9
|
+
/** Original pasted URL (normalized). */
|
|
10
|
+
url: string;
|
|
11
|
+
/** iframe src when the provider supports embed; null → link-out only. */
|
|
12
|
+
embedUrl: string | null;
|
|
13
|
+
label: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Normalize + validate a mood track URL for storage.
|
|
17
|
+
* Empty / whitespace → null. Unsupported host → throws with a host-facing message.
|
|
18
|
+
*/
|
|
19
|
+
export declare function normalizeMoodTrackUrl(raw: string | null | undefined): string | null;
|
|
20
|
+
/** Parse a mood URL into an embed plan (or null if unsupported). */
|
|
21
|
+
export declare function parseMoodTrackUrl(raw: string | null | undefined): MoodTrackEmbed | null;
|
|
22
|
+
export declare function isMoodTrackUrlAllowed(raw: string | null | undefined): boolean;
|
|
23
|
+
//# sourceMappingURL=moodTrackUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moodTrackUtils.d.ts","sourceRoot":"","sources":["../../src/utils/moodTrackUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,iBAAiB,GACzB,cAAc,GACd,SAAS,GACT,YAAY,GACZ,YAAY,CAAC;AAEjB,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAyEF;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC7B,MAAM,GAAG,IAAI,CAWf;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC7B,cAAc,GAAG,IAAI,CAsEvB;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAG7E"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bash mood track — optional soundtrack URL on a bash.
|
|
3
|
+
* Preferred: YouTube Music. Also: Spotify, Apple Music, SoundCloud.
|
|
4
|
+
* Guests tap to play; never autoplay.
|
|
5
|
+
*/
|
|
6
|
+
const YOUTUBE_HOSTS = new Set([
|
|
7
|
+
"music.youtube.com",
|
|
8
|
+
"www.youtube.com",
|
|
9
|
+
"youtube.com",
|
|
10
|
+
"youtu.be",
|
|
11
|
+
"m.youtube.com",
|
|
12
|
+
]);
|
|
13
|
+
const SPOTIFY_HOSTS = new Set(["open.spotify.com", "spotify.com"]);
|
|
14
|
+
const APPLE_HOSTS = new Set(["music.apple.com", "itunes.apple.com"]);
|
|
15
|
+
const SOUNDCLOUD_HOSTS = new Set(["soundcloud.com", "www.soundcloud.com", "m.soundcloud.com"]);
|
|
16
|
+
function hostnameOf(raw) {
|
|
17
|
+
try {
|
|
18
|
+
return new URL(raw).hostname.toLowerCase();
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function ensureHttps(raw) {
|
|
25
|
+
const trimmed = raw.trim();
|
|
26
|
+
if (!trimmed)
|
|
27
|
+
return null;
|
|
28
|
+
const withScheme = /^https?:\/\//i.test(trimmed)
|
|
29
|
+
? trimmed
|
|
30
|
+
: `https://${trimmed}`;
|
|
31
|
+
try {
|
|
32
|
+
const u = new URL(withScheme);
|
|
33
|
+
if (u.protocol !== "http:" && u.protocol !== "https:")
|
|
34
|
+
return null;
|
|
35
|
+
return u.toString();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function youtubeVideoId(url) {
|
|
42
|
+
if (url.hostname === "youtu.be") {
|
|
43
|
+
const id = url.pathname.replace(/^\//, "").split("/")[0];
|
|
44
|
+
return id || null;
|
|
45
|
+
}
|
|
46
|
+
const v = url.searchParams.get("v");
|
|
47
|
+
if (v)
|
|
48
|
+
return v;
|
|
49
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
50
|
+
const watchIdx = parts.indexOf("watch");
|
|
51
|
+
if (watchIdx >= 0 && parts[watchIdx + 1])
|
|
52
|
+
return parts[watchIdx + 1];
|
|
53
|
+
const embedIdx = parts.indexOf("embed");
|
|
54
|
+
if (embedIdx >= 0 && parts[embedIdx + 1])
|
|
55
|
+
return parts[embedIdx + 1];
|
|
56
|
+
const shortsIdx = parts.indexOf("shorts");
|
|
57
|
+
if (shortsIdx >= 0 && parts[shortsIdx + 1])
|
|
58
|
+
return parts[shortsIdx + 1];
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function youtubePlaylistId(url) {
|
|
62
|
+
return url.searchParams.get("list");
|
|
63
|
+
}
|
|
64
|
+
function spotifyEmbedPath(url) {
|
|
65
|
+
// /track/id | /album/id | /playlist/id | /episode/id
|
|
66
|
+
const m = url.pathname.match(/^\/(track|album|playlist|episode|show)\/([a-zA-Z0-9]+)/);
|
|
67
|
+
if (!m)
|
|
68
|
+
return null;
|
|
69
|
+
return `/${m[1]}/${m[2]}`;
|
|
70
|
+
}
|
|
71
|
+
function appleEmbedPath(url) {
|
|
72
|
+
// music.apple.com/{country}/album/... or /song/...
|
|
73
|
+
if (!url.pathname || url.pathname === "/")
|
|
74
|
+
return null;
|
|
75
|
+
return url.pathname + url.search;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Normalize + validate a mood track URL for storage.
|
|
79
|
+
* Empty / whitespace → null. Unsupported host → throws with a host-facing message.
|
|
80
|
+
*/
|
|
81
|
+
export function normalizeMoodTrackUrl(raw) {
|
|
82
|
+
if (raw == null)
|
|
83
|
+
return null;
|
|
84
|
+
const trimmed = raw.trim();
|
|
85
|
+
if (!trimmed)
|
|
86
|
+
return null;
|
|
87
|
+
const parsed = parseMoodTrackUrl(trimmed);
|
|
88
|
+
if (!parsed) {
|
|
89
|
+
throw new Error("Use a YouTube Music, Spotify, Apple Music, or SoundCloud link.");
|
|
90
|
+
}
|
|
91
|
+
return parsed.url;
|
|
92
|
+
}
|
|
93
|
+
/** Parse a mood URL into an embed plan (or null if unsupported). */
|
|
94
|
+
export function parseMoodTrackUrl(raw) {
|
|
95
|
+
const https = ensureHttps(raw ?? "");
|
|
96
|
+
if (!https)
|
|
97
|
+
return null;
|
|
98
|
+
let url;
|
|
99
|
+
try {
|
|
100
|
+
url = new URL(https);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const host = hostnameOf(https);
|
|
106
|
+
if (!host)
|
|
107
|
+
return null;
|
|
108
|
+
if (YOUTUBE_HOSTS.has(host)) {
|
|
109
|
+
const videoId = youtubeVideoId(url);
|
|
110
|
+
const listId = youtubePlaylistId(url);
|
|
111
|
+
if (videoId) {
|
|
112
|
+
const embed = new URL(`https://www.youtube.com/embed/${videoId}`);
|
|
113
|
+
embed.searchParams.set("playsinline", "1");
|
|
114
|
+
embed.searchParams.set("rel", "0");
|
|
115
|
+
if (listId)
|
|
116
|
+
embed.searchParams.set("list", listId);
|
|
117
|
+
return {
|
|
118
|
+
provider: "youtubeMusic",
|
|
119
|
+
url: https,
|
|
120
|
+
embedUrl: embed.toString(),
|
|
121
|
+
label: "YouTube Music",
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (listId) {
|
|
125
|
+
return {
|
|
126
|
+
provider: "youtubeMusic",
|
|
127
|
+
url: https,
|
|
128
|
+
embedUrl: `https://www.youtube.com/embed/videoseries?list=${encodeURIComponent(listId)}`,
|
|
129
|
+
label: "YouTube Music",
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
if (SPOTIFY_HOSTS.has(host)) {
|
|
135
|
+
const path = spotifyEmbedPath(url);
|
|
136
|
+
if (!path)
|
|
137
|
+
return null;
|
|
138
|
+
return {
|
|
139
|
+
provider: "spotify",
|
|
140
|
+
url: https,
|
|
141
|
+
embedUrl: `https://open.spotify.com/embed${path}`,
|
|
142
|
+
label: "Spotify",
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (APPLE_HOSTS.has(host)) {
|
|
146
|
+
const path = appleEmbedPath(url);
|
|
147
|
+
if (!path)
|
|
148
|
+
return null;
|
|
149
|
+
return {
|
|
150
|
+
provider: "appleMusic",
|
|
151
|
+
url: https,
|
|
152
|
+
embedUrl: `https://embed.music.apple.com${path}`,
|
|
153
|
+
label: "Apple Music",
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (SOUNDCLOUD_HOSTS.has(host)) {
|
|
157
|
+
return {
|
|
158
|
+
provider: "soundcloud",
|
|
159
|
+
url: https,
|
|
160
|
+
embedUrl: `https://w.soundcloud.com/player/?url=${encodeURIComponent(https)}&auto_play=false&hide_related=true&show_comments=false&visual=false`,
|
|
161
|
+
label: "SoundCloud",
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
export function isMoodTrackUrlAllowed(raw) {
|
|
167
|
+
if (raw == null || !String(raw).trim())
|
|
168
|
+
return true;
|
|
169
|
+
return parseMoodTrackUrl(raw) != null;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=moodTrackUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moodTrackUtils.js","sourceRoot":"","sources":["../../src/utils/moodTrackUtils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/prisma/schema.prisma
CHANGED
|
@@ -789,6 +789,8 @@ model BashEvent {
|
|
|
789
789
|
dateTimePublished DateTime?
|
|
790
790
|
includedItems String[]
|
|
791
791
|
videoLink String?
|
|
792
|
+
/// Optional mood track URL (YouTube Music preferred; Spotify / Apple Music / SoundCloud also OK).
|
|
793
|
+
moodTrackUrl String?
|
|
792
794
|
subtitle String?
|
|
793
795
|
isFeatured Boolean?
|
|
794
796
|
featuredUntil DateTime? // When paid feature expires (null = no expiry / super-user pinned)
|
|
@@ -4186,6 +4188,10 @@ model User {
|
|
|
4186
4188
|
referredById String?
|
|
4187
4189
|
referralPurchaseCredited Boolean @default(false)
|
|
4188
4190
|
|
|
4191
|
+
/// Best home-hero “Stuff the horn” clear time (ms). Lower is better; null = never cleared.
|
|
4192
|
+
hornClearBestMs Int?
|
|
4193
|
+
hornClearBestAt DateTime?
|
|
4194
|
+
|
|
4189
4195
|
// Security Fields
|
|
4190
4196
|
accountLockedUntil DateTime? // Account lockout timestamp for failed login protection
|
|
4191
4197
|
revokedTokens RevokedToken[] @relation("RevokedTokens") // Revoked JWT tokens
|
|
@@ -4368,6 +4374,7 @@ model User {
|
|
|
4368
4374
|
productLaunchRankSubmissions ProductLaunchRankSubmission[]
|
|
4369
4375
|
enterpriseLeads EnterpriseLead[]
|
|
4370
4376
|
feedbackTeamApplications FeedbackTeamApplication[]
|
|
4377
|
+
newsletterSubscriptions NewsletterSubscriber[]
|
|
4371
4378
|
pushNotificationTokens PushNotificationToken[]
|
|
4372
4379
|
redeemedVouchers Voucher[]
|
|
4373
4380
|
bashEventPromoCodesIUsed BashEventPromoCode[] @relation("BashEventPromoCodeToUser")
|
|
@@ -12548,3 +12555,22 @@ model FeedbackTeamApplication {
|
|
|
12548
12555
|
@@index([createdAt])
|
|
12549
12556
|
@@index([userId])
|
|
12550
12557
|
}
|
|
12558
|
+
|
|
12559
|
+
/// Platform newsletter / weekly roundup capture (footer + home). Not org-scoped — see OrganizationSubscriber.
|
|
12560
|
+
model NewsletterSubscriber {
|
|
12561
|
+
id String @id @default(cuid())
|
|
12562
|
+
email String @unique
|
|
12563
|
+
userId String?
|
|
12564
|
+
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
|
12565
|
+
/// Capture surface: footer | weekly_roundup
|
|
12566
|
+
source String @default("footer")
|
|
12567
|
+
/// Optional city context when signing up from a city roundup rail
|
|
12568
|
+
city String?
|
|
12569
|
+
createdAt DateTime @default(now())
|
|
12570
|
+
updatedAt DateTime @updatedAt
|
|
12571
|
+
unsubscribedAt DateTime?
|
|
12572
|
+
|
|
12573
|
+
@@index([createdAt])
|
|
12574
|
+
@@index([userId])
|
|
12575
|
+
@@index([source])
|
|
12576
|
+
}
|