@stackframe/stack-shared 2.8.28 → 2.8.31
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/CHANGELOG.md +18 -0
- package/dist/config/schema.d.mts +391 -15
- package/dist/config/schema.d.ts +391 -15
- package/dist/config/schema.js +70 -2
- package/dist/config/schema.js.map +1 -1
- package/dist/esm/config/schema.js +70 -3
- package/dist/esm/config/schema.js.map +1 -1
- package/dist/esm/interface/admin-interface.js +62 -0
- package/dist/esm/interface/admin-interface.js.map +1 -1
- package/dist/esm/interface/crud/projects.js +7 -1
- package/dist/esm/interface/crud/projects.js.map +1 -1
- package/dist/esm/known-errors.js +89 -1
- package/dist/esm/known-errors.js.map +1 -1
- package/dist/esm/schema-fields.js +67 -4
- package/dist/esm/schema-fields.js.map +1 -1
- package/dist/esm/utils/featurebase.js +176 -0
- package/dist/esm/utils/featurebase.js.map +1 -0
- package/dist/esm/utils/html.js +6 -1
- package/dist/esm/utils/html.js.map +1 -1
- package/dist/interface/admin-interface.d.mts +19 -0
- package/dist/interface/admin-interface.d.ts +19 -0
- package/dist/interface/admin-interface.js +62 -0
- package/dist/interface/admin-interface.js.map +1 -1
- package/dist/interface/crud/project-api-keys.d.mts +4 -4
- package/dist/interface/crud/project-api-keys.d.ts +4 -4
- package/dist/interface/crud/projects.d.mts +45 -7
- package/dist/interface/crud/projects.d.ts +45 -7
- package/dist/interface/crud/projects.js +7 -1
- package/dist/interface/crud/projects.js.map +1 -1
- package/dist/known-errors.d.mts +18 -0
- package/dist/known-errors.d.ts +18 -0
- package/dist/known-errors.js +89 -1
- package/dist/known-errors.js.map +1 -1
- package/dist/schema-fields.d.mts +88 -2
- package/dist/schema-fields.d.ts +88 -2
- package/dist/schema-fields.js +71 -3
- package/dist/schema-fields.js.map +1 -1
- package/dist/utils/featurebase.d.mts +28 -0
- package/dist/utils/featurebase.d.ts +28 -0
- package/dist/utils/featurebase.js +201 -0
- package/dist/utils/featurebase.js.map +1 -0
- package/dist/utils/html.d.mts +2 -1
- package/dist/utils/html.d.ts +2 -1
- package/dist/utils/html.js +8 -2
- package/dist/utils/html.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/utils/featurebase.tsx
|
|
21
|
+
var featurebase_exports = {};
|
|
22
|
+
__export(featurebase_exports, {
|
|
23
|
+
getOrCreateFeaturebaseUser: () => getOrCreateFeaturebaseUser
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(featurebase_exports);
|
|
26
|
+
var import_env = require("./env.js");
|
|
27
|
+
var import_errors = require("./errors.js");
|
|
28
|
+
async function findFeaturebaseUserById(stackAuthUserId, apiKey) {
|
|
29
|
+
try {
|
|
30
|
+
const response = await fetch(`https://do.featurebase.app/v2/organization/identifyUser?id=${stackAuthUserId}`, {
|
|
31
|
+
method: "GET",
|
|
32
|
+
headers: {
|
|
33
|
+
"X-API-Key": apiKey
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
if (response.status === 404) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
throw new import_errors.StackAssertionError(`Failed to find Featurebase user by ID: ${response.statusText}`);
|
|
41
|
+
}
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
const user = data.user;
|
|
44
|
+
if (!user) {
|
|
45
|
+
throw new import_errors.StackAssertionError(`Featurebase API returned success but no user data for ID: ${stackAuthUserId}`, { data });
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
userId: user.externalUserId || user.userId || stackAuthUserId,
|
|
49
|
+
email: user.email,
|
|
50
|
+
name: user.name,
|
|
51
|
+
profilePicture: user.profilePicture
|
|
52
|
+
};
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error instanceof import_errors.StackAssertionError) {
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
throw new import_errors.StackAssertionError("Failed to find Featurebase user by ID", { cause: error });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function findFeaturebaseUserByEmail(email, apiKey) {
|
|
61
|
+
try {
|
|
62
|
+
const response = await fetch(`https://do.featurebase.app/v2/organization/identifyUser?email=${encodeURIComponent(email)}`, {
|
|
63
|
+
method: "GET",
|
|
64
|
+
headers: {
|
|
65
|
+
"X-API-Key": apiKey
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
if (response.status === 404) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
throw new import_errors.StackAssertionError(`Failed to find Featurebase user by email: ${response.statusText}`);
|
|
73
|
+
}
|
|
74
|
+
const data = await response.json();
|
|
75
|
+
const user = data.user;
|
|
76
|
+
if (!user) {
|
|
77
|
+
throw new import_errors.StackAssertionError(`Featurebase API returned success but no user data for email: ${email}`, { data });
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
userId: user.externalUserId || user.userId,
|
|
81
|
+
email: user.email,
|
|
82
|
+
name: user.name,
|
|
83
|
+
profilePicture: user.profilePicture
|
|
84
|
+
};
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error("Error finding Featurebase user by email:", error);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function createFeaturebaseUser(user, apiKey) {
|
|
91
|
+
try {
|
|
92
|
+
const response = await fetch("https://do.featurebase.app/v2/organization/identifyUser", {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: {
|
|
95
|
+
"Content-Type": "application/json",
|
|
96
|
+
"X-API-Key": apiKey
|
|
97
|
+
},
|
|
98
|
+
body: JSON.stringify({
|
|
99
|
+
userId: user.userId,
|
|
100
|
+
email: user.email,
|
|
101
|
+
name: user.name,
|
|
102
|
+
profilePicture: user.profilePicture
|
|
103
|
+
})
|
|
104
|
+
});
|
|
105
|
+
if (!response.ok) {
|
|
106
|
+
const errorData = await response.json().catch(() => ({}));
|
|
107
|
+
throw new import_errors.StackAssertionError(`Failed to create Featurebase user: ${errorData.error || response.statusText}`, { errorData });
|
|
108
|
+
}
|
|
109
|
+
return user;
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error instanceof import_errors.StackAssertionError) {
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
throw new import_errors.StackAssertionError("Failed to create Featurebase user", { cause: error });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function updateFeaturebaseUser(userId, updates, apiKey) {
|
|
118
|
+
try {
|
|
119
|
+
const response = await fetch(`https://do.featurebase.app/v2/users/${userId}`, {
|
|
120
|
+
method: "PATCH",
|
|
121
|
+
headers: {
|
|
122
|
+
"Content-Type": "application/json",
|
|
123
|
+
"X-API-Key": apiKey
|
|
124
|
+
},
|
|
125
|
+
body: JSON.stringify(updates)
|
|
126
|
+
});
|
|
127
|
+
if (!response.ok) {
|
|
128
|
+
const errorData = await response.json().catch(() => ({}));
|
|
129
|
+
throw new import_errors.StackAssertionError(`Failed to update Featurebase user: ${errorData.error || response.statusText}`, { errorData });
|
|
130
|
+
}
|
|
131
|
+
const data = await response.json();
|
|
132
|
+
return {
|
|
133
|
+
userId: data.userId || userId,
|
|
134
|
+
email: data.email,
|
|
135
|
+
name: data.name,
|
|
136
|
+
profilePicture: data.profilePicture
|
|
137
|
+
};
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (error instanceof import_errors.StackAssertionError) {
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
throw new import_errors.StackAssertionError("Failed to update Featurebase user", { cause: error });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async function getOrCreateFeaturebaseUser(stackAuthUser, options) {
|
|
146
|
+
const apiKey = options?.apiKey || (0, import_env.getEnvVariable)("STACK_FEATUREBASE_API_KEY");
|
|
147
|
+
const fallbackEmail = `${stackAuthUser.id}@featurebase-user.stack-auth-app.com`;
|
|
148
|
+
const existingById = await findFeaturebaseUserById(stackAuthUser.id, apiKey);
|
|
149
|
+
if (existingById) {
|
|
150
|
+
let ensuredEmail = existingById.email;
|
|
151
|
+
if (!ensuredEmail) {
|
|
152
|
+
try {
|
|
153
|
+
await createFeaturebaseUser({
|
|
154
|
+
userId: existingById.userId,
|
|
155
|
+
email: fallbackEmail,
|
|
156
|
+
name: stackAuthUser.displayName || void 0,
|
|
157
|
+
profilePicture: stackAuthUser.profileImageUrl || void 0
|
|
158
|
+
}, apiKey);
|
|
159
|
+
ensuredEmail = fallbackEmail;
|
|
160
|
+
} catch (e) {
|
|
161
|
+
throw new import_errors.StackAssertionError(`Failed to set fallback email for existing Featurebase user ${existingById.userId}`, { cause: e });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
const updates = {};
|
|
166
|
+
if (stackAuthUser.displayName && stackAuthUser.displayName !== existingById.name) {
|
|
167
|
+
updates.name = stackAuthUser.displayName;
|
|
168
|
+
}
|
|
169
|
+
if (stackAuthUser.profileImageUrl && stackAuthUser.profileImageUrl !== existingById.profilePicture) {
|
|
170
|
+
updates.profilePicture = stackAuthUser.profileImageUrl;
|
|
171
|
+
}
|
|
172
|
+
if (Object.keys(updates).length > 0) {
|
|
173
|
+
await updateFeaturebaseUser(existingById.userId, updates, apiKey);
|
|
174
|
+
}
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error("Failed to update existing Featurebase user profile:", error);
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
userId: existingById.userId,
|
|
180
|
+
email: ensuredEmail
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const candidateEmail = stackAuthUser.primaryEmail ?? fallbackEmail;
|
|
184
|
+
const existingByEmail = await findFeaturebaseUserByEmail(candidateEmail, apiKey);
|
|
185
|
+
const safeEmail = existingByEmail ? fallbackEmail : candidateEmail;
|
|
186
|
+
const created = await createFeaturebaseUser({
|
|
187
|
+
userId: stackAuthUser.id,
|
|
188
|
+
email: safeEmail,
|
|
189
|
+
name: stackAuthUser.displayName || stackAuthUser.primaryEmail?.split("@")[0] || "User",
|
|
190
|
+
profilePicture: stackAuthUser.profileImageUrl || void 0
|
|
191
|
+
}, apiKey);
|
|
192
|
+
return {
|
|
193
|
+
userId: created.userId,
|
|
194
|
+
email: created.email
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
198
|
+
0 && (module.exports = {
|
|
199
|
+
getOrCreateFeaturebaseUser
|
|
200
|
+
});
|
|
201
|
+
//# sourceMappingURL=featurebase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/featurebase.tsx"],"sourcesContent":["import { getEnvVariable } from \"./env\";\nimport { StackAssertionError } from \"./errors\";\n\nexport type FeaturebaseUser = {\n userId: string,\n email: string,\n name?: string,\n profilePicture?: string,\n};\n\nexport type StackAuthUser = {\n id: string,\n primaryEmail: string | null,\n displayName?: string | null,\n profileImageUrl?: string | null,\n};\n\n/**\n * Find a Featurebase user by their Stack Auth user ID\n */\nasync function findFeaturebaseUserById(stackAuthUserId: string, apiKey: string): Promise<FeaturebaseUser | null> {\n try {\n const response = await fetch(`https://do.featurebase.app/v2/organization/identifyUser?id=${stackAuthUserId}`, {\n method: 'GET',\n headers: {\n 'X-API-Key': apiKey,\n },\n });\n\n if (response.status === 404) {\n return null;\n }\n\n if (!response.ok) {\n throw new StackAssertionError(`Failed to find Featurebase user by ID: ${response.statusText}`);\n }\n\n const data = await response.json();\n const user = data.user;\n\n if (!user) {\n throw new StackAssertionError(`Featurebase API returned success but no user data for ID: ${stackAuthUserId}`, { data });\n }\n\n return {\n userId: user.externalUserId || user.userId || stackAuthUserId,\n email: user.email,\n name: user.name,\n profilePicture: user.profilePicture,\n };\n } catch (error) {\n if (error instanceof StackAssertionError) {\n throw error;\n }\n throw new StackAssertionError(\"Failed to find Featurebase user by ID\", { cause: error });\n }\n}\n\n/**\n * Find a Featurebase user by their email address\n */\nasync function findFeaturebaseUserByEmail(email: string, apiKey: string): Promise<FeaturebaseUser | null> {\n try {\n const response = await fetch(`https://do.featurebase.app/v2/organization/identifyUser?email=${encodeURIComponent(email)}`, {\n method: 'GET',\n headers: {\n 'X-API-Key': apiKey,\n },\n });\n\n if (response.status === 404) {\n return null;\n }\n\n if (!response.ok) {\n throw new StackAssertionError(`Failed to find Featurebase user by email: ${response.statusText}`);\n }\n\n const data = await response.json();\n const user = data.user;\n\n if (!user) {\n throw new StackAssertionError(`Featurebase API returned success but no user data for email: ${email}`, { data });\n }\n\n return {\n userId: user.externalUserId || user.userId,\n email: user.email,\n name: user.name,\n profilePicture: user.profilePicture,\n };\n } catch (error) {\n console.error('Error finding Featurebase user by email:', error);\n return null;\n }\n}\n\n/**\n * Create a new Featurebase user using the identifyUser endpoint\n */\nasync function createFeaturebaseUser(user: FeaturebaseUser, apiKey: string): Promise<FeaturebaseUser> {\n try {\n const response = await fetch('https://do.featurebase.app/v2/organization/identifyUser', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify({\n userId: user.userId,\n email: user.email,\n name: user.name,\n profilePicture: user.profilePicture,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new StackAssertionError(`Failed to create Featurebase user: ${errorData.error || response.statusText}`, { errorData });\n }\n\n // The identifyUser endpoint just returns { \"success\": true }, so we return the input data\n return user;\n } catch (error) {\n if (error instanceof StackAssertionError) {\n throw error;\n }\n throw new StackAssertionError(\"Failed to create Featurebase user\", { cause: error });\n\n }\n}\n\n/**\n * Update an existing Featurebase user (excluding email)\n */\nasync function updateFeaturebaseUser(userId: string, updates: Partial<Omit<FeaturebaseUser, 'userId' | 'email'>>, apiKey: string): Promise<FeaturebaseUser> {\n try {\n const response = await fetch(`https://do.featurebase.app/v2/users/${userId}`, {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify(updates),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new StackAssertionError(`Failed to update Featurebase user: ${errorData.error || response.statusText}`, { errorData });\n }\n\n const data = await response.json();\n return {\n userId: data.userId || userId,\n email: data.email,\n name: data.name,\n profilePicture: data.profilePicture,\n };\n } catch (error) {\n if (error instanceof StackAssertionError) {\n throw error;\n }\n throw new StackAssertionError(\"Failed to update Featurebase user\", { cause: error });\n }\n}\n\n/**\n * Get or create a Featurebase user based on Stack Auth user data.\n * This function ensures that:\n * 1. We never change a user's email address on Featurebase\n * 2. We use Stack Auth user ID as the primary identifier\n * 3. We handle email conflicts by using fallback emails\n * 4. We update profile information when needed\n */\nexport async function getOrCreateFeaturebaseUser(\n stackAuthUser: StackAuthUser,\n options?: { apiKey?: string }\n): Promise<{ userId: string, email: string }> {\n const apiKey = options?.apiKey || getEnvVariable(\"STACK_FEATUREBASE_API_KEY\");\n const fallbackEmail = `${stackAuthUser.id}@featurebase-user.stack-auth-app.com`;\n\n // First, try to find existing user by Stack Auth user ID\n const existingById = await findFeaturebaseUserById(stackAuthUser.id, apiKey);\n if (existingById) {\n // Ensure the user has an email on Featurebase.\n let ensuredEmail = existingById.email;\n if (!ensuredEmail) {\n try {\n await createFeaturebaseUser({\n userId: existingById.userId,\n email: fallbackEmail,\n name: stackAuthUser.displayName || undefined,\n profilePicture: stackAuthUser.profileImageUrl || undefined,\n }, apiKey);\n ensuredEmail = fallbackEmail;\n } catch (e) {\n // If setting fallback email failed, keep ensuredEmail as-is (undefined) and let callers handle\n throw new StackAssertionError(`Failed to set fallback email for existing Featurebase user ${existingById.userId}`, { cause: e });\n }\n }\n\n // Update profile information if needed (but not email)\n try {\n const updates: Partial<Omit<FeaturebaseUser, 'userId' | 'email'>> = {};\n\n if (stackAuthUser.displayName && stackAuthUser.displayName !== existingById.name) {\n updates.name = stackAuthUser.displayName;\n }\n\n if (stackAuthUser.profileImageUrl && stackAuthUser.profileImageUrl !== existingById.profilePicture) {\n updates.profilePicture = stackAuthUser.profileImageUrl;\n }\n\n if (Object.keys(updates).length > 0) {\n await updateFeaturebaseUser(existingById.userId, updates, apiKey);\n }\n } catch (error) {\n console.error('Failed to update existing Featurebase user profile:', error);\n // Continue with existing user data even if update fails\n }\n\n return {\n userId: existingById.userId,\n email: ensuredEmail,\n };\n }\n\n // No existing user found by ID, need to create one\n const candidateEmail = stackAuthUser.primaryEmail ?? fallbackEmail;\n\n // Check if someone already has this email on Featurebase\n const existingByEmail = await findFeaturebaseUserByEmail(candidateEmail, apiKey);\n const safeEmail = existingByEmail ? fallbackEmail : candidateEmail;\n\n // Create new user\n const created = await createFeaturebaseUser({\n userId: stackAuthUser.id,\n email: safeEmail,\n name: stackAuthUser.displayName || stackAuthUser.primaryEmail?.split('@')[0] || 'User',\n profilePicture: stackAuthUser.profileImageUrl || undefined,\n }, apiKey);\n\n return {\n userId: created.userId,\n email: created.email,\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/utils/html.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
declare function escapeHtml(unsafe: string): string;
|
|
2
2
|
declare function html(strings: TemplateStringsArray, ...values: any[]): string;
|
|
3
|
+
declare function htmlToText(untrustedHtml: string): string;
|
|
3
4
|
|
|
4
|
-
export { escapeHtml, html };
|
|
5
|
+
export { escapeHtml, html, htmlToText };
|
package/dist/utils/html.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
declare function escapeHtml(unsafe: string): string;
|
|
2
2
|
declare function html(strings: TemplateStringsArray, ...values: any[]): string;
|
|
3
|
+
declare function htmlToText(untrustedHtml: string): string;
|
|
3
4
|
|
|
4
|
-
export { escapeHtml, html };
|
|
5
|
+
export { escapeHtml, html, htmlToText };
|
package/dist/utils/html.js
CHANGED
|
@@ -21,7 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var html_exports = {};
|
|
22
22
|
__export(html_exports, {
|
|
23
23
|
escapeHtml: () => escapeHtml,
|
|
24
|
-
html: () => html
|
|
24
|
+
html: () => html,
|
|
25
|
+
htmlToText: () => htmlToText
|
|
25
26
|
});
|
|
26
27
|
module.exports = __toCommonJS(html_exports);
|
|
27
28
|
var import_strings = require("./strings.js");
|
|
@@ -31,9 +32,14 @@ function escapeHtml(unsafe) {
|
|
|
31
32
|
function html(strings, ...values) {
|
|
32
33
|
return (0, import_strings.templateIdentity)(strings, ...values.map((v) => escapeHtml(`${v}`)));
|
|
33
34
|
}
|
|
35
|
+
function htmlToText(untrustedHtml) {
|
|
36
|
+
const doc = new DOMParser().parseFromString(untrustedHtml, "text/html");
|
|
37
|
+
return doc.body.textContent ?? "";
|
|
38
|
+
}
|
|
34
39
|
// Annotate the CommonJS export names for ESM import in node:
|
|
35
40
|
0 && (module.exports = {
|
|
36
41
|
escapeHtml,
|
|
37
|
-
html
|
|
42
|
+
html,
|
|
43
|
+
htmlToText
|
|
38
44
|
});
|
|
39
45
|
//# sourceMappingURL=html.js.map
|
package/dist/utils/html.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/html.tsx"],"sourcesContent":["import { templateIdentity } from \"./strings\";\n\nexport function escapeHtml(unsafe: string): string {\n return `${unsafe}`\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\nundefined?.test(\"escapeHtml\", ({ expect }) => {\n // Test with empty string\n expect(escapeHtml(\"\")).toBe(\"\");\n\n // Test with string without special characters\n expect(escapeHtml(\"hello world\")).toBe(\"hello world\");\n\n // Test with special characters\n expect(escapeHtml(\"<div>\")).toBe(\"<div>\");\n expect(escapeHtml(\"a & b\")).toBe(\"a & b\");\n expect(escapeHtml('a \"quoted\" string')).toBe(\"a "quoted" string\");\n expect(escapeHtml(\"it's a test\")).toBe(\"it's a test\");\n\n // Test with multiple special characters\n expect(escapeHtml(\"<a href=\\\"test\\\">It's a link</a>\")).toBe(\n \"<a href="test">It's a link</a>\"\n );\n});\n\nexport function html(strings: TemplateStringsArray, ...values: any[]): string {\n return templateIdentity(strings, ...values.map(v => escapeHtml(`${v}`)));\n}\nundefined?.test(\"html\", ({ expect }) => {\n // Test with no interpolation\n expect(html`simple string`).toBe(\"simple string\");\n\n // Test with string interpolation\n expect(html`Hello, ${\"world\"}!`).toBe(\"Hello, world!\");\n\n // Test with number interpolation\n expect(html`Count: ${42}`).toBe(\"Count: 42\");\n\n // Test with HTML special characters in interpolated values\n expect(html`<div>${\"<script>\"}</div>`).toBe(\"<div><script></div>\");\n\n // Test with multiple interpolations\n expect(html`${1} + ${2} = ${\"<3\"}`).toBe(\"1 + 2 = <3\");\n\n // Test with object interpolation\n const obj = { toString: () => \"<object>\" };\n expect(html`Object: ${obj}`).toBe(\"Object: <object>\");\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAiC;AAE1B,SAAS,WAAW,QAAwB;AACjD,SAAO,GAAG,MAAM,GACb,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AAoBO,SAAS,KAAK,YAAkC,QAAuB;AAC5E,aAAO,iCAAiB,SAAS,GAAG,OAAO,IAAI,OAAK,WAAW,GAAG,CAAC,EAAE,CAAC,CAAC;AACzE;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/html.tsx"],"sourcesContent":["import { templateIdentity } from \"./strings\";\n\nexport function escapeHtml(unsafe: string): string {\n return `${unsafe}`\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\nundefined?.test(\"escapeHtml\", ({ expect }) => {\n // Test with empty string\n expect(escapeHtml(\"\")).toBe(\"\");\n\n // Test with string without special characters\n expect(escapeHtml(\"hello world\")).toBe(\"hello world\");\n\n // Test with special characters\n expect(escapeHtml(\"<div>\")).toBe(\"<div>\");\n expect(escapeHtml(\"a & b\")).toBe(\"a & b\");\n expect(escapeHtml('a \"quoted\" string')).toBe(\"a "quoted" string\");\n expect(escapeHtml(\"it's a test\")).toBe(\"it's a test\");\n\n // Test with multiple special characters\n expect(escapeHtml(\"<a href=\\\"test\\\">It's a link</a>\")).toBe(\n \"<a href="test">It's a link</a>\"\n );\n});\n\nexport function html(strings: TemplateStringsArray, ...values: any[]): string {\n return templateIdentity(strings, ...values.map(v => escapeHtml(`${v}`)));\n}\nundefined?.test(\"html\", ({ expect }) => {\n // Test with no interpolation\n expect(html`simple string`).toBe(\"simple string\");\n\n // Test with string interpolation\n expect(html`Hello, ${\"world\"}!`).toBe(\"Hello, world!\");\n\n // Test with number interpolation\n expect(html`Count: ${42}`).toBe(\"Count: 42\");\n\n // Test with HTML special characters in interpolated values\n expect(html`<div>${\"<script>\"}</div>`).toBe(\"<div><script></div>\");\n\n // Test with multiple interpolations\n expect(html`${1} + ${2} = ${\"<3\"}`).toBe(\"1 + 2 = <3\");\n\n // Test with object interpolation\n const obj = { toString: () => \"<object>\" };\n expect(html`Object: ${obj}`).toBe(\"Object: <object>\");\n});\n\nexport function htmlToText(untrustedHtml: string): string {\n\n const doc = new DOMParser().parseFromString(untrustedHtml, 'text/html');\n\n return doc.body.textContent ?? '';\n\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAiC;AAE1B,SAAS,WAAW,QAAwB;AACjD,SAAO,GAAG,MAAM,GACb,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AAoBO,SAAS,KAAK,YAAkC,QAAuB;AAC5E,aAAO,iCAAiB,SAAS,GAAG,OAAO,IAAI,OAAK,WAAW,GAAG,CAAC,EAAE,CAAC,CAAC;AACzE;AAsBO,SAAS,WAAW,eAA+B;AAExD,QAAM,MAAM,IAAI,UAAU,EAAE,gBAAgB,eAAe,WAAW;AAEtE,SAAO,IAAI,KAAK,eAAe;AAEjC;","names":[]}
|