@happyvertical/smrt-profiles 0.37.2 → 0.37.3
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/chunks/ApiKey-3DlNEc91.js +145 -0
- package/dist/chunks/ApiKey-3DlNEc91.js.map +1 -0
- package/dist/chunks/ApiKeyCollection-PwVs0qDb.js +83 -0
- package/dist/chunks/ApiKeyCollection-PwVs0qDb.js.map +1 -0
- package/dist/chunks/AuditLogCollection-CnIYU0aK.js +191 -0
- package/dist/chunks/AuditLogCollection-CnIYU0aK.js.map +1 -0
- package/dist/chunks/NostrIdentityCollection-CG6HGf6c.js +3267 -0
- package/dist/chunks/NostrIdentityCollection-CG6HGf6c.js.map +1 -0
- package/dist/chunks/OidcIdentityCollection-DiLneB7J.js +158 -0
- package/dist/chunks/OidcIdentityCollection-DiLneB7J.js.map +1 -0
- package/dist/chunks/ProfileAssetCollection-BY2Wbem3.js +93 -0
- package/dist/chunks/ProfileAssetCollection-BY2Wbem3.js.map +1 -0
- package/dist/chunks/ProfileCollection-DlhdOnDr.js +641 -0
- package/dist/chunks/ProfileCollection-DlhdOnDr.js.map +1 -0
- package/dist/chunks/ProfileMetadataCollection-CGcO4Iw_.js +105 -0
- package/dist/chunks/ProfileMetadataCollection-CGcO4Iw_.js.map +1 -0
- package/dist/chunks/ProfileMetafieldCollection-C8TX9HvN.js +142 -0
- package/dist/chunks/ProfileMetafieldCollection-C8TX9HvN.js.map +1 -0
- package/dist/chunks/ProfileRelationshipCollection-JnskbZTd.js +159 -0
- package/dist/chunks/ProfileRelationshipCollection-JnskbZTd.js.map +1 -0
- package/dist/chunks/ProfileRelationshipTermCollection-UopP7sja.js +105 -0
- package/dist/chunks/ProfileRelationshipTermCollection-UopP7sja.js.map +1 -0
- package/dist/chunks/ProfileRelationshipType-OMBn5cWR.js +98 -0
- package/dist/chunks/ProfileRelationshipType-OMBn5cWR.js.map +1 -0
- package/dist/chunks/ProfileRelationshipTypeCollection-CQu08kxF.js +54 -0
- package/dist/chunks/ProfileRelationshipTypeCollection-CQu08kxF.js.map +1 -0
- package/dist/index.js +690 -69
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +2 -2
- package/dist/smrt-knowledge.json +9 -9
- package/dist/types.js +0 -2
- package/dist/utils.js +18 -36
- package/dist/utils.js.map +1 -1
- package/package.json +16 -16
- package/dist/chunks/ApiKey-B2LKEaP8.js +0 -143
- package/dist/chunks/ApiKey-B2LKEaP8.js.map +0 -1
- package/dist/chunks/ApiKeyCollection-B6Op817e.js +0 -91
- package/dist/chunks/ApiKeyCollection-B6Op817e.js.map +0 -1
- package/dist/chunks/AuditLogCollection-BYqCj0uE.js +0 -195
- package/dist/chunks/AuditLogCollection-BYqCj0uE.js.map +0 -1
- package/dist/chunks/NostrIdentityCollection-DadQBHWy.js +0 -3065
- package/dist/chunks/NostrIdentityCollection-DadQBHWy.js.map +0 -1
- package/dist/chunks/ProfileAssetCollection-CUM5QfuJ.js +0 -122
- package/dist/chunks/ProfileAssetCollection-CUM5QfuJ.js.map +0 -1
- package/dist/chunks/ProfileCollection-M2PK8bp-.js +0 -800
- package/dist/chunks/ProfileCollection-M2PK8bp-.js.map +0 -1
- package/dist/chunks/ProfileMetadataCollection-DEhmljMY.js +0 -120
- package/dist/chunks/ProfileMetadataCollection-DEhmljMY.js.map +0 -1
- package/dist/chunks/ProfileMetafieldCollection-DMKhSHXX.js +0 -184
- package/dist/chunks/ProfileMetafieldCollection-DMKhSHXX.js.map +0 -1
- package/dist/chunks/ProfileRelationshipCollection-_TsY7MHL.js +0 -189
- package/dist/chunks/ProfileRelationshipCollection-_TsY7MHL.js.map +0 -1
- package/dist/chunks/ProfileRelationshipTermCollection-CXem_qT-.js +0 -117
- package/dist/chunks/ProfileRelationshipTermCollection-CXem_qT-.js.map +0 -1
- package/dist/chunks/ProfileRelationshipType-BXBLldea.js +0 -103
- package/dist/chunks/ProfileRelationshipType-BXBLldea.js.map +0 -1
- package/dist/chunks/ProfileRelationshipTypeCollection-CF8YvLTV.js +0 -48
- package/dist/chunks/ProfileRelationshipTypeCollection-CF8YvLTV.js.map +0 -1
- package/dist/chunks/index-B9lXQy7N.js +0 -1029
- package/dist/chunks/index-B9lXQy7N.js.map +0 -1
- package/dist/types.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,70 +1,691 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
P as Person,
|
|
28
|
-
a2 as Profile,
|
|
29
|
-
P3 as ProfileAsset,
|
|
30
|
-
a5 as ProfileAssetCollection,
|
|
31
|
-
b2 as ProfileCollection,
|
|
32
|
-
P4 as ProfileMetadata,
|
|
33
|
-
a6 as ProfileMetadataCollection,
|
|
34
|
-
P5 as ProfileMetafield,
|
|
35
|
-
a7 as ProfileMetafieldCollection,
|
|
36
|
-
P6 as ProfileRelationship,
|
|
37
|
-
a8 as ProfileRelationshipCollection,
|
|
38
|
-
P7 as ProfileRelationshipTerm,
|
|
39
|
-
a9 as ProfileRelationshipTermCollection,
|
|
40
|
-
ProfileRelationshipType,
|
|
41
|
-
ProfileRelationshipTypeCollection,
|
|
42
|
-
P2 as ProfileType,
|
|
43
|
-
d as ProfileTypeCollection,
|
|
44
|
-
c2 as computeEventId,
|
|
45
|
-
b3 as createAuthEvent,
|
|
46
|
-
e as createMagicLinkService,
|
|
47
|
-
f as createNip05Handler,
|
|
48
|
-
g as createProfileFromNostr,
|
|
49
|
-
h as createProfileFromOidc,
|
|
50
|
-
d2 as decryptPrivkey,
|
|
51
|
-
f2 as deriveEncryptionKey,
|
|
52
|
-
e2 as encryptPrivkey,
|
|
53
|
-
g2 as generateNostrKeypair,
|
|
54
|
-
h2 as getPublicKey,
|
|
55
|
-
i as isValidNip05Identifier,
|
|
56
|
-
i2 as isValidPrivkey,
|
|
57
|
-
j as isValidPubkey,
|
|
58
|
-
n as npubToPubkey,
|
|
59
|
-
k as nsecToPrivkey,
|
|
60
|
-
p as parseNip05Identifier,
|
|
61
|
-
p3 as privkeyToNsec,
|
|
62
|
-
p2 as promptMessageOptions,
|
|
63
|
-
l as pubkeyToNpub,
|
|
64
|
-
r as resolveIdentity,
|
|
65
|
-
s2 as signEvent,
|
|
66
|
-
s as smrtProfilesGenerateBioPrompt,
|
|
67
|
-
v as verifyAuthEvent,
|
|
68
|
-
m as verifyNostrSignature
|
|
1
|
+
import { _ as pubkeyToNpub, a as computeEventId, b as verifyNostrSignature, c as deriveEncryptionKey, d as getPublicKey, f as isValidPrivkey, g as privkeyToNsec, h as nsecToPrivkey, l as encryptPrivkey, m as npubToPubkey, o as createAuthEvent, p as isValidPubkey, r as NostrIdentity, s as decryptPrivkey, t as NostrIdentityCollection, u as generateNostrKeypair, v as signEvent, x as __exportAll, y as verifyAuthEvent } from "./chunks/NostrIdentityCollection-CG6HGf6c.js";
|
|
2
|
+
import { i as ProfileType, o as promptMessageOptions, r as Profile, s as smrtProfilesGenerateBioPrompt, t as ProfileCollection } from "./chunks/ProfileCollection-DlhdOnDr.js";
|
|
3
|
+
import { t as ApiKey } from "./chunks/ApiKey-3DlNEc91.js";
|
|
4
|
+
import { r as OidcIdentity, t as OidcIdentityCollection } from "./chunks/OidcIdentityCollection-DiLneB7J.js";
|
|
5
|
+
import { t as ApiKeyCollection } from "./chunks/ApiKeyCollection-PwVs0qDb.js";
|
|
6
|
+
import { r as AuditLog, t as AuditLogCollection } from "./chunks/AuditLogCollection-CnIYU0aK.js";
|
|
7
|
+
import { r as ProfileAsset, t as ProfileAssetCollection } from "./chunks/ProfileAssetCollection-BY2Wbem3.js";
|
|
8
|
+
import { r as ProfileMetadata, t as ProfileMetadataCollection } from "./chunks/ProfileMetadataCollection-CGcO4Iw_.js";
|
|
9
|
+
import { r as ProfileMetafield, t as ProfileMetafieldCollection } from "./chunks/ProfileMetafieldCollection-C8TX9HvN.js";
|
|
10
|
+
import { r as ProfileRelationship, t as ProfileRelationshipCollection } from "./chunks/ProfileRelationshipCollection-JnskbZTd.js";
|
|
11
|
+
import { r as ProfileRelationshipTerm, t as ProfileRelationshipTermCollection } from "./chunks/ProfileRelationshipTermCollection-UopP7sja.js";
|
|
12
|
+
import { t as ProfileRelationshipType } from "./chunks/ProfileRelationshipType-OMBn5cWR.js";
|
|
13
|
+
import { t as ProfileRelationshipTypeCollection } from "./chunks/ProfileRelationshipTypeCollection-CQu08kxF.js";
|
|
14
|
+
import { ObjectRegistry, SmrtCollection, SmrtObject, foreignKey, smrt } from "@happyvertical/smrt-core";
|
|
15
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
16
|
+
//#region src/__smrt-register__.ts
|
|
17
|
+
ObjectRegistry.registerPackageManifest(new URL("./manifest.json", "" + import.meta.url));
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/models/MagicLinkToken.ts
|
|
20
|
+
var __defProp$1 = Object.defineProperty;
|
|
21
|
+
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
22
|
+
var __decorateClass$1 = (decorators, target, key, kind) => {
|
|
23
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
|
|
24
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
25
|
+
if (kind && result) __defProp$1(target, key, result);
|
|
26
|
+
return result;
|
|
69
27
|
};
|
|
70
|
-
|
|
28
|
+
var DEFAULT_EXPIRATION_MINUTES = 15;
|
|
29
|
+
var MagicLinkToken = class extends SmrtObject {
|
|
30
|
+
nostrIdentityId;
|
|
31
|
+
/**
|
|
32
|
+
* SHA-256 hash of the token (never store plaintext)
|
|
33
|
+
*/
|
|
34
|
+
tokenHash = "";
|
|
35
|
+
/**
|
|
36
|
+
* Email this token was sent to
|
|
37
|
+
*/
|
|
38
|
+
email = "";
|
|
39
|
+
/**
|
|
40
|
+
* When this token expires
|
|
41
|
+
*/
|
|
42
|
+
expiresAt = new Date(Date.now() + DEFAULT_EXPIRATION_MINUTES * 60 * 1e3);
|
|
43
|
+
/**
|
|
44
|
+
* When this token was used (null = unused)
|
|
45
|
+
*/
|
|
46
|
+
usedAt = null;
|
|
47
|
+
/**
|
|
48
|
+
* IP address that requested the token (for rate limiting)
|
|
49
|
+
*/
|
|
50
|
+
requestedFromIp = "";
|
|
51
|
+
/**
|
|
52
|
+
* When this token was created (for rate limiting)
|
|
53
|
+
*/
|
|
54
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
55
|
+
constructor(options = {}) {
|
|
56
|
+
super(options);
|
|
57
|
+
if (options.nostrIdentityId) this.nostrIdentityId = options.nostrIdentityId;
|
|
58
|
+
if (options.tokenHash) this.tokenHash = options.tokenHash;
|
|
59
|
+
if (options.email) this.email = options.email;
|
|
60
|
+
if (options.expiresAt) this.expiresAt = options.expiresAt;
|
|
61
|
+
if (options.usedAt !== void 0) this.usedAt = options.usedAt;
|
|
62
|
+
if (options.requestedFromIp) this.requestedFromIp = options.requestedFromIp;
|
|
63
|
+
if (options.createdAt) this.createdAt = options.createdAt;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Hash a token using SHA-256
|
|
67
|
+
*/
|
|
68
|
+
static hashToken(token) {
|
|
69
|
+
return createHash("sha256").update(token).digest("hex");
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Generate a new magic link token
|
|
73
|
+
* @param nostrIdentity - The identity this token is for
|
|
74
|
+
* @param email - The email address to send to
|
|
75
|
+
* @param options - Additional options
|
|
76
|
+
*/
|
|
77
|
+
static async generate(nostrIdentity, email, options = {}) {
|
|
78
|
+
const token = randomBytes(32).toString("base64url");
|
|
79
|
+
const tokenHash = MagicLinkToken.hashToken(token);
|
|
80
|
+
const expiresInMinutes = options.expiresInMinutes ?? DEFAULT_EXPIRATION_MINUTES;
|
|
81
|
+
const expiresAt = new Date(Date.now() + expiresInMinutes * 60 * 1e3);
|
|
82
|
+
const magicLinkToken = new MagicLinkToken({
|
|
83
|
+
db: options.db ?? nostrIdentity.options?.db,
|
|
84
|
+
nostrIdentityId: nostrIdentity.id,
|
|
85
|
+
tokenHash,
|
|
86
|
+
email: email.toLowerCase(),
|
|
87
|
+
expiresAt,
|
|
88
|
+
requestedFromIp: options.requestedFromIp || ""
|
|
89
|
+
});
|
|
90
|
+
await magicLinkToken.initialize();
|
|
91
|
+
await magicLinkToken.save();
|
|
92
|
+
return {
|
|
93
|
+
token,
|
|
94
|
+
magicLinkToken
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Verify a token and return the MagicLinkToken if valid
|
|
99
|
+
* @param token - The plaintext token to verify
|
|
100
|
+
* @param options - Database options
|
|
101
|
+
* @returns The MagicLinkToken if valid, null otherwise
|
|
102
|
+
*/
|
|
103
|
+
static async verify(token, options = {}) {
|
|
104
|
+
const tokenHash = MagicLinkToken.hashToken(token);
|
|
105
|
+
const { MagicLinkTokenCollection } = await Promise.resolve().then(() => MagicLinkTokenCollection_exports);
|
|
106
|
+
const magicLinkToken = await (await MagicLinkTokenCollection.create(options)).findOne({ where: { tokenHash } });
|
|
107
|
+
if (!magicLinkToken) return null;
|
|
108
|
+
if (!magicLinkToken.isValid()) return null;
|
|
109
|
+
return magicLinkToken;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Check if this token is valid (not expired and not used)
|
|
113
|
+
*/
|
|
114
|
+
isValid() {
|
|
115
|
+
if (this.usedAt !== null) return false;
|
|
116
|
+
if (/* @__PURE__ */ new Date() > this.expiresAt) return false;
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Check if this token has expired
|
|
121
|
+
*/
|
|
122
|
+
isExpired() {
|
|
123
|
+
return /* @__PURE__ */ new Date() > this.expiresAt;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check if this token has been used
|
|
127
|
+
*/
|
|
128
|
+
isUsed() {
|
|
129
|
+
return this.usedAt !== null;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Mark this token as used
|
|
133
|
+
*/
|
|
134
|
+
async markUsed() {
|
|
135
|
+
this.usedAt = /* @__PURE__ */ new Date();
|
|
136
|
+
await this.save();
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get the NostrIdentity this token is for
|
|
140
|
+
*/
|
|
141
|
+
async getNostrIdentity() {
|
|
142
|
+
return await this.getRelated("nostrIdentityId");
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get time remaining until expiration in seconds
|
|
146
|
+
*/
|
|
147
|
+
getTimeRemainingSeconds() {
|
|
148
|
+
const now = /* @__PURE__ */ new Date();
|
|
149
|
+
const diff = this.expiresAt.getTime() - now.getTime();
|
|
150
|
+
return Math.max(0, Math.floor(diff / 1e3));
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
__decorateClass$1([foreignKey("NostrIdentity", { required: true })], MagicLinkToken.prototype, "nostrIdentityId", 2);
|
|
154
|
+
MagicLinkToken = __decorateClass$1([smrt({
|
|
155
|
+
tableName: "magic_link_tokens",
|
|
156
|
+
api: { exclude: ["*"] },
|
|
157
|
+
mcp: { exclude: ["*"] },
|
|
158
|
+
cli: { include: ["list"] }
|
|
159
|
+
})], MagicLinkToken);
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/collections/MagicLinkTokenCollection.ts
|
|
162
|
+
var MagicLinkTokenCollection_exports = /* @__PURE__ */ __exportAll({ MagicLinkTokenCollection: () => MagicLinkTokenCollection });
|
|
163
|
+
var MagicLinkTokenCollection = class extends SmrtCollection {
|
|
164
|
+
static _itemClass = MagicLinkToken;
|
|
165
|
+
/**
|
|
166
|
+
* Find token by hash
|
|
167
|
+
*/
|
|
168
|
+
async findByTokenHash(tokenHash) {
|
|
169
|
+
return await this.findOne({ where: { tokenHash } });
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Find active (non-expired, non-used) tokens for an email
|
|
173
|
+
*/
|
|
174
|
+
async findActiveForEmail(email) {
|
|
175
|
+
return (await this.list({ where: { email: email.toLowerCase() } })).filter((token) => token.isValid());
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Find tokens for a NostrIdentity
|
|
179
|
+
*/
|
|
180
|
+
async findByIdentity(nostrIdentityId) {
|
|
181
|
+
return await this.list({ where: { nostrIdentityId } });
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Count tokens created for an email within a time window (for rate limiting)
|
|
185
|
+
* @param email - Email address
|
|
186
|
+
* @param withinMinutes - Time window in minutes
|
|
187
|
+
*/
|
|
188
|
+
async countRecentByEmail(email, withinMinutes) {
|
|
189
|
+
const cutoff = /* @__PURE__ */ new Date(Date.now() - withinMinutes * 60 * 1e3);
|
|
190
|
+
return (await this.list({ where: { email: email.toLowerCase() } })).filter((token) => {
|
|
191
|
+
const createdAt = token.createdAt;
|
|
192
|
+
return createdAt && new Date(createdAt) > cutoff;
|
|
193
|
+
}).length;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Count tokens created from an IP within a time window (for rate limiting)
|
|
197
|
+
* @param ip - IP address
|
|
198
|
+
* @param withinMinutes - Time window in minutes
|
|
199
|
+
*/
|
|
200
|
+
async countRecentByIp(ip, withinMinutes) {
|
|
201
|
+
const cutoff = /* @__PURE__ */ new Date(Date.now() - withinMinutes * 60 * 1e3);
|
|
202
|
+
return (await this.list({ where: { requestedFromIp: ip } })).filter((token) => {
|
|
203
|
+
const createdAt = token.createdAt;
|
|
204
|
+
return createdAt && new Date(createdAt) > cutoff;
|
|
205
|
+
}).length;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Verify a token and return it if valid
|
|
209
|
+
*/
|
|
210
|
+
async verify(token) {
|
|
211
|
+
const tokenHash = MagicLinkToken.hashToken(token);
|
|
212
|
+
const magicLinkToken = await this.findByTokenHash(tokenHash);
|
|
213
|
+
if (!magicLinkToken) return null;
|
|
214
|
+
if (!magicLinkToken.isValid()) return null;
|
|
215
|
+
return magicLinkToken;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Clean up expired tokens by deleting them
|
|
219
|
+
* @returns Number of tokens deleted
|
|
220
|
+
*/
|
|
221
|
+
async cleanupExpired() {
|
|
222
|
+
const allTokens = await this.list({});
|
|
223
|
+
let deleted = 0;
|
|
224
|
+
for (const token of allTokens) if (token.isExpired() || token.isUsed()) {
|
|
225
|
+
await token.delete();
|
|
226
|
+
deleted++;
|
|
227
|
+
}
|
|
228
|
+
return deleted;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Revoke all tokens for a NostrIdentity (e.g., when identity is deleted)
|
|
232
|
+
*/
|
|
233
|
+
async revokeForIdentity(nostrIdentityId) {
|
|
234
|
+
const tokens = await this.findByIdentity(nostrIdentityId);
|
|
235
|
+
let revoked = 0;
|
|
236
|
+
for (const token of tokens) if (!token.isUsed()) {
|
|
237
|
+
await token.markUsed();
|
|
238
|
+
revoked++;
|
|
239
|
+
}
|
|
240
|
+
return revoked;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Check if rate limit is exceeded for email
|
|
244
|
+
* @param email - Email address
|
|
245
|
+
* @param maxPerHour - Maximum tokens allowed per hour (default: 5)
|
|
246
|
+
*/
|
|
247
|
+
async isRateLimitedByEmail(email, maxPerHour = 5) {
|
|
248
|
+
return await this.countRecentByEmail(email, 60) >= maxPerHour;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Check if rate limit is exceeded for IP
|
|
252
|
+
* @param ip - IP address
|
|
253
|
+
* @param maxPerHour - Maximum tokens allowed per hour (default: 10)
|
|
254
|
+
*/
|
|
255
|
+
async isRateLimitedByIp(ip, maxPerHour = 10) {
|
|
256
|
+
return await this.countRecentByIp(ip, 60) >= maxPerHour;
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
//#endregion
|
|
260
|
+
//#region src/auth/magicLinkService.ts
|
|
261
|
+
function createMagicLinkService(config) {
|
|
262
|
+
const { baseUrl, verifyPath = "/auth/verify", expiresInMinutes = 15, maxTokensPerEmailPerHour = 5, maxTokensPerIpPerHour = 10, masterSecret, sendEmail, db } = config;
|
|
263
|
+
return {
|
|
264
|
+
async initiate(email, options = {}) {
|
|
265
|
+
const normalizedEmail = email.toLowerCase().trim();
|
|
266
|
+
const { requestedFromIp, nip05Username } = options;
|
|
267
|
+
const identityCollection = await NostrIdentityCollection.create({ db });
|
|
268
|
+
const tokenCollection = await MagicLinkTokenCollection.create({ db });
|
|
269
|
+
if (await tokenCollection.isRateLimitedByEmail(normalizedEmail, maxTokensPerEmailPerHour)) return {
|
|
270
|
+
success: false,
|
|
271
|
+
created: false,
|
|
272
|
+
error: "Too many requests for this email. Please try again later.",
|
|
273
|
+
errorCode: "RATE_LIMITED_EMAIL"
|
|
274
|
+
};
|
|
275
|
+
if (requestedFromIp && await tokenCollection.isRateLimitedByIp(requestedFromIp, maxTokensPerIpPerHour)) return {
|
|
276
|
+
success: false,
|
|
277
|
+
created: false,
|
|
278
|
+
error: "Too many requests from this IP. Please try again later.",
|
|
279
|
+
errorCode: "RATE_LIMITED_IP"
|
|
280
|
+
};
|
|
281
|
+
let nostrIdentity = await identityCollection.findByEmail(normalizedEmail);
|
|
282
|
+
let profile = null;
|
|
283
|
+
let created = false;
|
|
284
|
+
if (!nostrIdentity) {
|
|
285
|
+
const { Person } = await Promise.resolve().then(() => ProfileTypes_exports);
|
|
286
|
+
const { ProfileTypeCollection } = await Promise.resolve().then(() => ProfileTypeCollection_exports);
|
|
287
|
+
let personType = await (await ProfileTypeCollection.create({ db })).getBySlug("person");
|
|
288
|
+
if (!personType) {
|
|
289
|
+
const { ProfileType } = await import("./chunks/ProfileCollection-DlhdOnDr.js").then((n) => n.a);
|
|
290
|
+
personType = new ProfileType({
|
|
291
|
+
db,
|
|
292
|
+
slug: "person",
|
|
293
|
+
name: "Person",
|
|
294
|
+
description: "Individual person profile"
|
|
295
|
+
});
|
|
296
|
+
await personType.initialize();
|
|
297
|
+
await personType.save();
|
|
298
|
+
}
|
|
299
|
+
profile = new Person({
|
|
300
|
+
db,
|
|
301
|
+
typeId: personType.id,
|
|
302
|
+
email: normalizedEmail,
|
|
303
|
+
name: normalizedEmail.split("@")[0]
|
|
304
|
+
});
|
|
305
|
+
await profile.initialize();
|
|
306
|
+
await profile.save();
|
|
307
|
+
const keypair = generateNostrKeypair();
|
|
308
|
+
const encrypted = encryptPrivkey(keypair.privkey, masterSecret);
|
|
309
|
+
const { NostrIdentity: NostrIdentityClass } = await import("./chunks/NostrIdentityCollection-CG6HGf6c.js").then((n) => n.i);
|
|
310
|
+
nostrIdentity = new NostrIdentityClass({
|
|
311
|
+
db,
|
|
312
|
+
profileId: profile.id,
|
|
313
|
+
pubkey: keypair.pubkey,
|
|
314
|
+
encryptedPrivkey: encrypted.ciphertext,
|
|
315
|
+
encryptionIv: encrypted.iv,
|
|
316
|
+
encryptionTag: encrypted.tag,
|
|
317
|
+
email: normalizedEmail,
|
|
318
|
+
nip05Username: nip05Username?.toLowerCase() || normalizedEmail.split("@")[0]
|
|
319
|
+
});
|
|
320
|
+
await nostrIdentity.initialize();
|
|
321
|
+
await nostrIdentity.save();
|
|
322
|
+
created = true;
|
|
323
|
+
} else profile = await nostrIdentity.getProfile();
|
|
324
|
+
const { token } = await MagicLinkToken.generate(nostrIdentity, normalizedEmail, {
|
|
325
|
+
expiresInMinutes,
|
|
326
|
+
requestedFromIp,
|
|
327
|
+
db
|
|
328
|
+
});
|
|
329
|
+
const magicLink = `${baseUrl}${verifyPath}?token=${encodeURIComponent(token)}`;
|
|
330
|
+
try {
|
|
331
|
+
await sendEmail(normalizedEmail, magicLink);
|
|
332
|
+
} catch (emailError) {
|
|
333
|
+
return {
|
|
334
|
+
success: false,
|
|
335
|
+
created,
|
|
336
|
+
nostrIdentity,
|
|
337
|
+
profile: profile || void 0,
|
|
338
|
+
error: "Failed to send email. Please try again.",
|
|
339
|
+
errorCode: "EMAIL_SEND_FAILED"
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
success: true,
|
|
344
|
+
created,
|
|
345
|
+
nostrIdentity,
|
|
346
|
+
profile: profile || void 0
|
|
347
|
+
};
|
|
348
|
+
},
|
|
349
|
+
async verify(token) {
|
|
350
|
+
const magicLinkToken = await MagicLinkToken.verify(token, { db });
|
|
351
|
+
if (!magicLinkToken) {
|
|
352
|
+
const tokenHash = MagicLinkToken.hashToken(token);
|
|
353
|
+
const existingToken = await (await MagicLinkTokenCollection.create({ db })).findByTokenHash(tokenHash);
|
|
354
|
+
if (!existingToken) return {
|
|
355
|
+
success: false,
|
|
356
|
+
error: "Invalid or expired token.",
|
|
357
|
+
errorCode: "NOT_FOUND"
|
|
358
|
+
};
|
|
359
|
+
if (existingToken.isUsed()) return {
|
|
360
|
+
success: false,
|
|
361
|
+
error: "This link has already been used.",
|
|
362
|
+
errorCode: "USED_TOKEN"
|
|
363
|
+
};
|
|
364
|
+
if (existingToken.isExpired()) return {
|
|
365
|
+
success: false,
|
|
366
|
+
error: "This link has expired. Please request a new one.",
|
|
367
|
+
errorCode: "EXPIRED_TOKEN"
|
|
368
|
+
};
|
|
369
|
+
return {
|
|
370
|
+
success: false,
|
|
371
|
+
error: "Invalid token.",
|
|
372
|
+
errorCode: "INVALID_TOKEN"
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
await magicLinkToken.markUsed();
|
|
376
|
+
const nostrIdentity = await magicLinkToken.getNostrIdentity();
|
|
377
|
+
if (!nostrIdentity) return {
|
|
378
|
+
success: false,
|
|
379
|
+
error: "Identity not found.",
|
|
380
|
+
errorCode: "NOT_FOUND"
|
|
381
|
+
};
|
|
382
|
+
await nostrIdentity.markVerified();
|
|
383
|
+
const profile = await nostrIdentity.getProfile();
|
|
384
|
+
const keypair = nostrIdentity.getKeypair(masterSecret);
|
|
385
|
+
return {
|
|
386
|
+
success: true,
|
|
387
|
+
profile: profile || void 0,
|
|
388
|
+
nostrIdentity,
|
|
389
|
+
keypair
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
//#endregion
|
|
395
|
+
//#region src/auth/nip05Handler.ts
|
|
396
|
+
function createNip05Handler(config) {
|
|
397
|
+
const { db, defaultRelays = [], cacheTtlSeconds = 300 } = config;
|
|
398
|
+
return async function handleNip05Request(request) {
|
|
399
|
+
const { name } = request;
|
|
400
|
+
const response = await (await NostrIdentityCollection.create({ db })).getNip05Response(name || void 0);
|
|
401
|
+
if (defaultRelays.length > 0 && Object.keys(response.names).length > 0) {
|
|
402
|
+
response.relays = {};
|
|
403
|
+
for (const pubkey of Object.values(response.names)) response.relays[pubkey] = defaultRelays;
|
|
404
|
+
}
|
|
405
|
+
if (name && Object.keys(response.names).length === 0) return {
|
|
406
|
+
body: { names: {} },
|
|
407
|
+
headers: {
|
|
408
|
+
"Content-Type": "application/json",
|
|
409
|
+
"Access-Control-Allow-Origin": "*",
|
|
410
|
+
"Cache-Control": `public, max-age=${cacheTtlSeconds}`
|
|
411
|
+
},
|
|
412
|
+
status: 200
|
|
413
|
+
};
|
|
414
|
+
return {
|
|
415
|
+
body: response,
|
|
416
|
+
headers: {
|
|
417
|
+
"Content-Type": "application/json",
|
|
418
|
+
"Access-Control-Allow-Origin": "*",
|
|
419
|
+
"Cache-Control": `public, max-age=${cacheTtlSeconds}`
|
|
420
|
+
},
|
|
421
|
+
status: 200
|
|
422
|
+
};
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
function isValidNip05Identifier(identifier) {
|
|
426
|
+
const parts = identifier.split("@");
|
|
427
|
+
if (parts.length !== 2) return false;
|
|
428
|
+
const [localPart, domain] = parts;
|
|
429
|
+
if (!/^[a-z0-9_-]+$/i.test(localPart)) return false;
|
|
430
|
+
if (!/^[a-z0-9.-]+\.[a-z]{2,}$/i.test(domain)) return false;
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
function parseNip05Identifier(identifier) {
|
|
434
|
+
if (!isValidNip05Identifier(identifier)) return null;
|
|
435
|
+
const [localPart, domain] = identifier.split("@");
|
|
436
|
+
return {
|
|
437
|
+
localPart,
|
|
438
|
+
domain
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/auth/resolveIdentity.ts
|
|
443
|
+
async function resolveIdentity(context) {
|
|
444
|
+
const options = { db: context.db };
|
|
445
|
+
if (context.apiKey) {
|
|
446
|
+
const apiKey = await ApiKey.verify(context.apiKey, options);
|
|
447
|
+
if (apiKey) {
|
|
448
|
+
const profile = await apiKey.getProfile();
|
|
449
|
+
if (profile) return {
|
|
450
|
+
profile,
|
|
451
|
+
source: "api_key",
|
|
452
|
+
apiKey
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (context.oidcSession?.sub && context.oidcSession?.iss) {
|
|
457
|
+
const oidcIdentity = await OidcIdentity.findBySubject(context.oidcSession.iss, context.oidcSession.sub, options);
|
|
458
|
+
if (oidcIdentity) {
|
|
459
|
+
await oidcIdentity.recordUsage();
|
|
460
|
+
const profile = await oidcIdentity.getProfile();
|
|
461
|
+
if (profile) return {
|
|
462
|
+
profile,
|
|
463
|
+
source: "oidc",
|
|
464
|
+
oidcIdentity
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (context.nostrAuth?.event && context.nostrAuth?.challenge) {
|
|
469
|
+
const { event, challenge } = context.nostrAuth;
|
|
470
|
+
if (verifyAuthEvent(event, challenge).valid) {
|
|
471
|
+
const nostrIdentity = await NostrIdentity.findByPubkey(event.pubkey, options);
|
|
472
|
+
if (nostrIdentity) {
|
|
473
|
+
await nostrIdentity.recordUsage();
|
|
474
|
+
const profile = await nostrIdentity.getProfile();
|
|
475
|
+
if (profile) return {
|
|
476
|
+
profile,
|
|
477
|
+
source: "nostr",
|
|
478
|
+
nostrIdentity
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (context.actor) {
|
|
484
|
+
const profile = await findProfileByExternalId("github", context.actor, options);
|
|
485
|
+
if (profile) return {
|
|
486
|
+
profile,
|
|
487
|
+
source: "actor"
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
return {
|
|
491
|
+
profile: null,
|
|
492
|
+
source: "none"
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
async function findProfileByExternalId(provider, externalId, options) {
|
|
496
|
+
const { OidcIdentityCollection } = await import("./chunks/OidcIdentityCollection-DiLneB7J.js").then((n) => n.n);
|
|
497
|
+
const identities = await (await OidcIdentityCollection.create(options)).findByProvider(provider);
|
|
498
|
+
for (const identity of identities) if (identity.subject === externalId || identity.email?.includes(externalId)) {
|
|
499
|
+
const profile = await identity.getProfile();
|
|
500
|
+
if (profile) return profile;
|
|
501
|
+
}
|
|
502
|
+
const { ProfileCollection } = await import("./chunks/ProfileCollection-DlhdOnDr.js").then((n) => n.n);
|
|
503
|
+
const profiles = await (await ProfileCollection.create(options)).list({
|
|
504
|
+
where: { email: `${externalId}@users.noreply.github.com` },
|
|
505
|
+
limit: 1
|
|
506
|
+
});
|
|
507
|
+
if (profiles.length > 0) return profiles[0];
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
async function createProfileFromOidc(claims, provider, options) {
|
|
511
|
+
const existingIdentity = await OidcIdentity.findBySubject(claims.iss, claims.sub, options);
|
|
512
|
+
if (existingIdentity) {
|
|
513
|
+
const profile2 = await existingIdentity.getProfile();
|
|
514
|
+
if (profile2) {
|
|
515
|
+
if (claims.email) existingIdentity.email = claims.email;
|
|
516
|
+
existingIdentity.lastUsedAt = /* @__PURE__ */ new Date();
|
|
517
|
+
await existingIdentity.save();
|
|
518
|
+
return {
|
|
519
|
+
profile: profile2,
|
|
520
|
+
oidcIdentity: existingIdentity,
|
|
521
|
+
created: false
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (claims.email && claims.email_verified) {
|
|
526
|
+
const { ProfileCollection } = await import("./chunks/ProfileCollection-DlhdOnDr.js").then((n) => n.n);
|
|
527
|
+
const existingProfile = await (await ProfileCollection.create(options)).findByEmail(claims.email);
|
|
528
|
+
if (existingProfile) return {
|
|
529
|
+
profile: existingProfile,
|
|
530
|
+
oidcIdentity: await OidcIdentity.findOrCreate(existingProfile, {
|
|
531
|
+
provider,
|
|
532
|
+
issuer: claims.iss,
|
|
533
|
+
subject: claims.sub,
|
|
534
|
+
email: claims.email
|
|
535
|
+
}, options),
|
|
536
|
+
created: false
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
const { Person } = await Promise.resolve().then(() => ProfileTypes_exports);
|
|
540
|
+
const { ProfileTypeCollection } = await Promise.resolve().then(() => ProfileTypeCollection_exports);
|
|
541
|
+
let personType = await (await ProfileTypeCollection.create(options)).getBySlug("person");
|
|
542
|
+
if (!personType) {
|
|
543
|
+
const { ProfileType } = await import("./chunks/ProfileCollection-DlhdOnDr.js").then((n) => n.a);
|
|
544
|
+
personType = new ProfileType({
|
|
545
|
+
...options,
|
|
546
|
+
slug: "person",
|
|
547
|
+
name: "Person",
|
|
548
|
+
description: "Individual person profile"
|
|
549
|
+
});
|
|
550
|
+
await personType.initialize();
|
|
551
|
+
await personType.save();
|
|
552
|
+
}
|
|
553
|
+
const profile = new Person({
|
|
554
|
+
...options,
|
|
555
|
+
typeId: personType.id,
|
|
556
|
+
email: claims.email || "",
|
|
557
|
+
name: claims.name || claims.preferred_username || claims.sub
|
|
558
|
+
});
|
|
559
|
+
await profile.initialize();
|
|
560
|
+
await profile.save();
|
|
561
|
+
return {
|
|
562
|
+
profile,
|
|
563
|
+
oidcIdentity: await OidcIdentity.findOrCreate(profile, {
|
|
564
|
+
provider,
|
|
565
|
+
issuer: claims.iss,
|
|
566
|
+
subject: claims.sub,
|
|
567
|
+
email: claims.email
|
|
568
|
+
}, options),
|
|
569
|
+
created: true
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
async function createProfileFromNostr(email, nostrData, options) {
|
|
573
|
+
const normalizedEmail = email.toLowerCase();
|
|
574
|
+
const existingIdentity = await NostrIdentity.findByEmail(normalizedEmail, options);
|
|
575
|
+
if (existingIdentity) {
|
|
576
|
+
const profile2 = await existingIdentity.getProfile();
|
|
577
|
+
if (profile2) return {
|
|
578
|
+
profile: profile2,
|
|
579
|
+
nostrIdentity: existingIdentity,
|
|
580
|
+
created: false
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const { Person } = await Promise.resolve().then(() => ProfileTypes_exports);
|
|
584
|
+
const { ProfileTypeCollection } = await Promise.resolve().then(() => ProfileTypeCollection_exports);
|
|
585
|
+
let personType = await (await ProfileTypeCollection.create(options)).getBySlug("person");
|
|
586
|
+
if (!personType) {
|
|
587
|
+
const { ProfileType } = await import("./chunks/ProfileCollection-DlhdOnDr.js").then((n) => n.a);
|
|
588
|
+
personType = new ProfileType({
|
|
589
|
+
...options,
|
|
590
|
+
slug: "person",
|
|
591
|
+
name: "Person",
|
|
592
|
+
description: "Individual person profile"
|
|
593
|
+
});
|
|
594
|
+
await personType.initialize();
|
|
595
|
+
await personType.save();
|
|
596
|
+
}
|
|
597
|
+
const profile = new Person({
|
|
598
|
+
...options,
|
|
599
|
+
typeId: personType.id,
|
|
600
|
+
email: normalizedEmail,
|
|
601
|
+
name: normalizedEmail.split("@")[0]
|
|
602
|
+
});
|
|
603
|
+
await profile.initialize();
|
|
604
|
+
await profile.save();
|
|
605
|
+
const nostrIdentity = new NostrIdentity({
|
|
606
|
+
...options,
|
|
607
|
+
profileId: profile.id,
|
|
608
|
+
pubkey: nostrData.pubkey,
|
|
609
|
+
encryptedPrivkey: nostrData.encryptedPrivkey,
|
|
610
|
+
encryptionIv: nostrData.encryptionIv,
|
|
611
|
+
encryptionTag: nostrData.encryptionTag,
|
|
612
|
+
email: normalizedEmail,
|
|
613
|
+
nip05Username: nostrData.nip05Username?.toLowerCase() || normalizedEmail.split("@")[0]
|
|
614
|
+
});
|
|
615
|
+
await nostrIdentity.initialize();
|
|
616
|
+
await nostrIdentity.save();
|
|
617
|
+
return {
|
|
618
|
+
profile,
|
|
619
|
+
nostrIdentity,
|
|
620
|
+
created: true
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
//#endregion
|
|
624
|
+
//#region src/collections/ProfileTypeCollection.ts
|
|
625
|
+
var ProfileTypeCollection_exports = /* @__PURE__ */ __exportAll({ ProfileTypeCollection: () => ProfileTypeCollection });
|
|
626
|
+
var ProfileTypeCollection = class extends SmrtCollection {
|
|
627
|
+
static _itemClass = ProfileType;
|
|
628
|
+
/**
|
|
629
|
+
* Get profile type by slug
|
|
630
|
+
*
|
|
631
|
+
* @param slug - The slug to search for
|
|
632
|
+
* @returns ProfileType instance or null
|
|
633
|
+
*/
|
|
634
|
+
async getBySlug(slug) {
|
|
635
|
+
return await this.get({ slug });
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Get or create a profile type by slug
|
|
639
|
+
*
|
|
640
|
+
* @param slug - The slug to search for
|
|
641
|
+
* @param defaults - Default values if creating
|
|
642
|
+
* @returns ProfileType instance
|
|
643
|
+
*/
|
|
644
|
+
async getOrCreateBySlug(slug, defaults) {
|
|
645
|
+
const existing = await this.getBySlug(slug);
|
|
646
|
+
if (existing) return existing;
|
|
647
|
+
const profileType = await this.create({
|
|
648
|
+
slug,
|
|
649
|
+
...defaults
|
|
650
|
+
});
|
|
651
|
+
await profileType.save();
|
|
652
|
+
return profileType;
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/models/ProfileTypes.ts
|
|
657
|
+
var ProfileTypes_exports = /* @__PURE__ */ __exportAll({
|
|
658
|
+
Bot: () => Bot,
|
|
659
|
+
Organization: () => Organization,
|
|
660
|
+
Person: () => Person
|
|
661
|
+
});
|
|
662
|
+
var __defProp = Object.defineProperty;
|
|
663
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
664
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
665
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
666
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
667
|
+
if (kind && result) __defProp(target, key, result);
|
|
668
|
+
return result;
|
|
669
|
+
};
|
|
670
|
+
var Person = class extends Profile {
|
|
671
|
+
constructor(options = {}) {
|
|
672
|
+
super(options);
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
Person = __decorateClass([smrt({ tableStrategy: "sti" })], Person);
|
|
676
|
+
var Organization = class extends Profile {
|
|
677
|
+
constructor(options = {}) {
|
|
678
|
+
super(options);
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
Organization = __decorateClass([smrt({ tableStrategy: "sti" })], Organization);
|
|
682
|
+
var Bot = class extends Profile {
|
|
683
|
+
constructor(options = {}) {
|
|
684
|
+
super(options);
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
Bot = __decorateClass([smrt({ tableStrategy: "sti" })], Bot);
|
|
688
|
+
//#endregion
|
|
689
|
+
export { ApiKey, ApiKeyCollection, AuditLog, AuditLogCollection, Bot, MagicLinkToken, MagicLinkTokenCollection, NostrIdentity, NostrIdentityCollection, OidcIdentity, OidcIdentityCollection, Organization, Person, Profile, ProfileAsset, ProfileAssetCollection, ProfileCollection, ProfileMetadata, ProfileMetadataCollection, ProfileMetafield, ProfileMetafieldCollection, ProfileRelationship, ProfileRelationshipCollection, ProfileRelationshipTerm, ProfileRelationshipTermCollection, ProfileRelationshipType, ProfileRelationshipTypeCollection, ProfileType, ProfileTypeCollection, computeEventId, createAuthEvent, createMagicLinkService, createNip05Handler, createProfileFromNostr, createProfileFromOidc, decryptPrivkey, deriveEncryptionKey, encryptPrivkey, generateNostrKeypair, getPublicKey, isValidNip05Identifier, isValidPrivkey, isValidPubkey, npubToPubkey, nsecToPrivkey, parseNip05Identifier, privkeyToNsec, promptMessageOptions, pubkeyToNpub, resolveIdentity, signEvent, smrtProfilesGenerateBioPrompt, verifyAuthEvent, verifyNostrSignature };
|
|
690
|
+
|
|
691
|
+
//# sourceMappingURL=index.js.map
|