@fabriktor/fx 0.0.16 → 0.0.18
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/src/core/err.d.ts +26 -0
- package/dist/src/core/err.js +82 -0
- package/dist/src/fx.d.ts +0 -1
- package/dist/src/fx.js +6 -3
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/session/session.d.ts +1 -1
- package/dist/src/users/username.js +8 -4
- package/dist/src/users/users.d.ts +3 -8
- package/dist/src/users/users.js +8 -38
- package/package.json +2 -2
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const FXErrKind: {
|
|
2
|
+
readonly UsernameResolveFailed: "username_resolve_failed";
|
|
3
|
+
readonly UsernameInvalid: "username_invalid";
|
|
4
|
+
readonly PhoneRequired: "phone_required";
|
|
5
|
+
readonly PhoneCodeRequired: "phone_code_required";
|
|
6
|
+
readonly Unknown: "unknown";
|
|
7
|
+
};
|
|
8
|
+
export type FXErrKind = (typeof FXErrKind)[keyof typeof FXErrKind];
|
|
9
|
+
export type FXErrOptions = {
|
|
10
|
+
kind: FXErrKind;
|
|
11
|
+
msg: string;
|
|
12
|
+
cause?: unknown;
|
|
13
|
+
};
|
|
14
|
+
export declare class FXErr extends Error {
|
|
15
|
+
readonly kind: FXErrKind;
|
|
16
|
+
readonly cause?: unknown;
|
|
17
|
+
constructor(opts: FXErrOptions);
|
|
18
|
+
}
|
|
19
|
+
export declare function errFX(opts: FXErrOptions): FXErr;
|
|
20
|
+
export declare function errUsernameResolveFailed(): FXErr;
|
|
21
|
+
export declare function errUsernameInvalid(msg: string): FXErr;
|
|
22
|
+
export declare function errPhoneRequired(): FXErr;
|
|
23
|
+
export declare function errPhoneCodeRequired(): FXErr;
|
|
24
|
+
export declare function errUnknown(cause: unknown): FXErr;
|
|
25
|
+
export declare function isFXErr(err: unknown): err is FXErr;
|
|
26
|
+
export declare function fxErrMessage(err: unknown): string;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Copyright (C) Fabriktor, Inc. 2025-present.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
4
|
+
// not use this file except in compliance with the License. You may obtain
|
|
5
|
+
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
const msgUnknownFXErr = "Unknown FX error.";
|
|
7
|
+
const msgUnableToResolveUsername = "Unable to resolve username.";
|
|
8
|
+
const msgPhoneRequired = "Phone number is required.";
|
|
9
|
+
const msgPhoneCodeRequired = "Verification code is required.";
|
|
10
|
+
export const FXErrKind = {
|
|
11
|
+
UsernameResolveFailed: "username_resolve_failed",
|
|
12
|
+
UsernameInvalid: "username_invalid",
|
|
13
|
+
PhoneRequired: "phone_required",
|
|
14
|
+
PhoneCodeRequired: "phone_code_required",
|
|
15
|
+
Unknown: "unknown",
|
|
16
|
+
};
|
|
17
|
+
export class FXErr extends Error {
|
|
18
|
+
kind;
|
|
19
|
+
cause;
|
|
20
|
+
constructor(opts) {
|
|
21
|
+
super(opts.msg);
|
|
22
|
+
this.name = new.target.name;
|
|
23
|
+
this.kind = opts.kind;
|
|
24
|
+
this.cause = opts.cause;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function errFX(opts) {
|
|
28
|
+
return new FXErr(opts);
|
|
29
|
+
}
|
|
30
|
+
export function errUsernameResolveFailed() {
|
|
31
|
+
return errFX({
|
|
32
|
+
kind: FXErrKind.UsernameResolveFailed,
|
|
33
|
+
msg: msgUnableToResolveUsername,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export function errUsernameInvalid(msg) {
|
|
37
|
+
return errFX({
|
|
38
|
+
kind: FXErrKind.UsernameInvalid,
|
|
39
|
+
msg,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
export function errPhoneRequired() {
|
|
43
|
+
return errFX({
|
|
44
|
+
kind: FXErrKind.PhoneRequired,
|
|
45
|
+
msg: msgPhoneRequired,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export function errPhoneCodeRequired() {
|
|
49
|
+
return errFX({
|
|
50
|
+
kind: FXErrKind.PhoneCodeRequired,
|
|
51
|
+
msg: msgPhoneCodeRequired,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export function errUnknown(cause) {
|
|
55
|
+
if (isFXErr(cause)) {
|
|
56
|
+
return cause;
|
|
57
|
+
}
|
|
58
|
+
if (cause instanceof Error) {
|
|
59
|
+
return errFX({
|
|
60
|
+
kind: FXErrKind.Unknown,
|
|
61
|
+
msg: cause.message,
|
|
62
|
+
cause,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return errFX({
|
|
66
|
+
kind: FXErrKind.Unknown,
|
|
67
|
+
msg: msgUnknownFXErr,
|
|
68
|
+
cause,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
export function isFXErr(err) {
|
|
72
|
+
return err instanceof FXErr;
|
|
73
|
+
}
|
|
74
|
+
export function fxErrMessage(err) {
|
|
75
|
+
if (isFXErr(err)) {
|
|
76
|
+
return err.message;
|
|
77
|
+
}
|
|
78
|
+
if (err instanceof Error) {
|
|
79
|
+
return err.message;
|
|
80
|
+
}
|
|
81
|
+
return msgUnknownFXErr;
|
|
82
|
+
}
|
package/dist/src/fx.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ import type { AuthOperator } from "./auth/auth.js";
|
|
|
3
3
|
import type { SessionFX, SessionFXOperator } from "./session/session.js";
|
|
4
4
|
import type { UsersFX, UsersFXOperator } from "./users/users.js";
|
|
5
5
|
export type FXOptions = {
|
|
6
|
-
base_url: string;
|
|
7
6
|
auth: AuthOperator;
|
|
8
7
|
users: UsersOperator;
|
|
9
8
|
tmp_usernames: TmpUsernamesOperator;
|
package/dist/src/fx.js
CHANGED
|
@@ -11,8 +11,6 @@ export class FX {
|
|
|
11
11
|
session;
|
|
12
12
|
constructor(opts) {
|
|
13
13
|
this.users = newUsersFX({
|
|
14
|
-
base_url: opts.base_url,
|
|
15
|
-
auth: opts.auth,
|
|
16
14
|
users: opts.users,
|
|
17
15
|
tmp_usernames: opts.tmp_usernames,
|
|
18
16
|
tmp_phones: opts.tmp_phones,
|
|
@@ -29,16 +27,21 @@ export function newFX(opts) {
|
|
|
29
27
|
export function newDefaultFX(opts) {
|
|
30
28
|
const http = newHTTPClient();
|
|
31
29
|
return newFX({
|
|
32
|
-
base_url: opts.base_url,
|
|
33
30
|
auth: opts.auth,
|
|
34
31
|
users: newUsersClient({
|
|
35
32
|
http,
|
|
33
|
+
base_url: opts.base_url,
|
|
34
|
+
get_token: () => opts.auth.getToken(),
|
|
36
35
|
}),
|
|
37
36
|
tmp_usernames: newTmpUsernamesClient({
|
|
38
37
|
http,
|
|
38
|
+
base_url: opts.base_url,
|
|
39
|
+
get_token: () => opts.auth.getToken(),
|
|
39
40
|
}),
|
|
40
41
|
tmp_phones: newTmpPhonesClient({
|
|
41
42
|
http,
|
|
43
|
+
base_url: opts.base_url,
|
|
44
|
+
get_token: () => opts.auth.getToken(),
|
|
42
45
|
}),
|
|
43
46
|
});
|
|
44
47
|
}
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { InUser, PLUsersForgotPassword, PLUsersSignInLink, UpsertResult } from "@fabriktor/schema";
|
|
2
1
|
import type { Op } from "@fabriktor/client";
|
|
2
|
+
import type { InUser, PLUsersForgotPassword, PLUsersSignInLink, UpsertResult } from "@fabriktor/schema";
|
|
3
3
|
import type { AuthEmailOptions, AuthOperator } from "../auth/auth.js";
|
|
4
4
|
import type { BootstrapOptions, UsersFXOperator } from "../users/users.js";
|
|
5
5
|
export type SignInMode = "email" | "username";
|
|
@@ -7,6 +7,10 @@ const usernameMinLength = 3;
|
|
|
7
7
|
const usernameMaxLength = 40;
|
|
8
8
|
const usernamePattern = /^[a-z][a-z0-9_]*$/;
|
|
9
9
|
const usernameLetterPattern = /[a-z]/;
|
|
10
|
+
const msgUsernameMinLength = "Username must contain at least 3 characters.";
|
|
11
|
+
const msgUsernameMaxLength = "Username must contain at most 40 characters.";
|
|
12
|
+
const msgUsernamePattern = "Username must start with a lowercase letter and contain only lowercase letters, digits, and underscores.";
|
|
13
|
+
const msgUsernameLetter = "Username must contain at least one letter.";
|
|
10
14
|
export function normalizeUsername(v) {
|
|
11
15
|
return v.trim().toLowerCase();
|
|
12
16
|
}
|
|
@@ -16,28 +20,28 @@ export function validateUsernameFormat(v) {
|
|
|
16
20
|
return {
|
|
17
21
|
valid: false,
|
|
18
22
|
normalized,
|
|
19
|
-
error:
|
|
23
|
+
error: msgUsernameMinLength,
|
|
20
24
|
};
|
|
21
25
|
}
|
|
22
26
|
if (normalized.length > usernameMaxLength) {
|
|
23
27
|
return {
|
|
24
28
|
valid: false,
|
|
25
29
|
normalized,
|
|
26
|
-
error:
|
|
30
|
+
error: msgUsernameMaxLength,
|
|
27
31
|
};
|
|
28
32
|
}
|
|
29
33
|
if (!usernamePattern.test(normalized)) {
|
|
30
34
|
return {
|
|
31
35
|
valid: false,
|
|
32
36
|
normalized,
|
|
33
|
-
error:
|
|
37
|
+
error: msgUsernamePattern,
|
|
34
38
|
};
|
|
35
39
|
}
|
|
36
40
|
if (!usernameLetterPattern.test(normalized)) {
|
|
37
41
|
return {
|
|
38
42
|
valid: false,
|
|
39
43
|
normalized,
|
|
40
|
-
error:
|
|
44
|
+
error: msgUsernameLetter,
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
47
|
return {
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { InUser, OperationResult, PLUsersContactList, PLUsersForgotPassword, PLUsersResolveUsername, PLUsersSendCode, PLUsersSignInLink, PLUsersUsername, PLUsersVerifyCode, UpsertResult, User } from "@fabriktor/schema";
|
|
2
|
-
import type {
|
|
3
|
-
import type { AuthOperator } from "../auth/auth.js";
|
|
2
|
+
import type { Op, TmpPhonesOperator, TmpUsernamesOperator, UsernameVerification, UsersOperator } from "@fabriktor/client";
|
|
4
3
|
export type UsersFXOptions = {
|
|
5
|
-
base_url: string;
|
|
6
|
-
auth: AuthOperator;
|
|
7
4
|
users: UsersOperator;
|
|
8
5
|
tmp_usernames: TmpUsernamesOperator;
|
|
9
6
|
tmp_phones: TmpPhonesOperator;
|
|
@@ -29,13 +26,11 @@ export interface UsersFXOperator {
|
|
|
29
26
|
generateUsernames(opts: PLUsersUsername): Promise<Op<UsernameVerification>>;
|
|
30
27
|
sendPhoneCode(opts: PLUsersSendCode): Promise<void>;
|
|
31
28
|
verifyPhoneCode(opts: PLUsersVerifyCode): Promise<void>;
|
|
32
|
-
match(opts: PLUsersContactList): Promise<Op<
|
|
29
|
+
match(opts: PLUsersContactList): Promise<Op<User[]>>;
|
|
33
30
|
search(opts: SearchOptions): Promise<Op<User[]>>;
|
|
34
31
|
getByUID(opts: GetByUIDOptions): Promise<Op<User>>;
|
|
35
32
|
}
|
|
36
33
|
export declare class UsersFX implements UsersFXOperator {
|
|
37
|
-
private base_url;
|
|
38
|
-
private auth;
|
|
39
34
|
private users;
|
|
40
35
|
private tmp_usernames;
|
|
41
36
|
private tmp_phones;
|
|
@@ -50,7 +45,7 @@ export declare class UsersFX implements UsersFXOperator {
|
|
|
50
45
|
generateUsernames(opts: PLUsersUsername): Promise<Op<UsernameVerification>>;
|
|
51
46
|
sendPhoneCode(opts: PLUsersSendCode): Promise<void>;
|
|
52
47
|
verifyPhoneCode(opts: PLUsersVerifyCode): Promise<void>;
|
|
53
|
-
match(opts: PLUsersContactList): Promise<Op<
|
|
48
|
+
match(opts: PLUsersContactList): Promise<Op<User[]>>;
|
|
54
49
|
search(opts: SearchOptions): Promise<Op<User[]>>;
|
|
55
50
|
getByUID(opts: GetByUIDOptions): Promise<Op<User>>;
|
|
56
51
|
}
|
package/dist/src/users/users.js
CHANGED
|
@@ -3,80 +3,61 @@
|
|
|
3
3
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
4
4
|
// not use this file except in compliance with the License. You may obtain
|
|
5
5
|
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
import { errPhoneCodeRequired, errPhoneRequired, errUsernameInvalid, errUsernameResolveFailed, } from "../core/err.js";
|
|
6
7
|
import { normalizePhone, normalizePhoneCode, validatePhone, validatePhoneCode, } from "./phone.js";
|
|
7
8
|
import { normalizeUsername, validateUsernameFormat } from "./username.js";
|
|
8
9
|
export class UsersFX {
|
|
9
|
-
base_url;
|
|
10
|
-
auth;
|
|
11
10
|
users;
|
|
12
11
|
tmp_usernames;
|
|
13
12
|
tmp_phones;
|
|
14
13
|
constructor(opts) {
|
|
15
|
-
this.base_url = opts.base_url;
|
|
16
|
-
this.auth = opts.auth;
|
|
17
14
|
this.users = opts.users;
|
|
18
15
|
this.tmp_usernames = opts.tmp_usernames;
|
|
19
16
|
this.tmp_phones = opts.tmp_phones;
|
|
20
17
|
}
|
|
21
18
|
async bootstrap(opts) {
|
|
22
|
-
const token = await this.auth.getToken();
|
|
23
19
|
return await this.users.bootstrap({
|
|
24
|
-
base_url: this.base_url,
|
|
25
|
-
token,
|
|
26
20
|
in: opts.in,
|
|
27
21
|
});
|
|
28
22
|
}
|
|
29
23
|
async sync() {
|
|
30
|
-
|
|
31
|
-
return await this.users.sync({
|
|
32
|
-
base_url: this.base_url,
|
|
33
|
-
token,
|
|
34
|
-
});
|
|
24
|
+
return await this.users.sync();
|
|
35
25
|
}
|
|
36
26
|
async sendEmailVerification() {
|
|
37
|
-
|
|
38
|
-
return await this.users.sendEmailVerification({
|
|
39
|
-
base_url: this.base_url,
|
|
40
|
-
token,
|
|
41
|
-
});
|
|
27
|
+
return await this.users.sendEmailVerification();
|
|
42
28
|
}
|
|
43
29
|
async forgotPassword(opts) {
|
|
44
30
|
return await this.users.forgotPassword({
|
|
45
|
-
base_url: this.base_url,
|
|
46
31
|
email: opts.email,
|
|
47
32
|
});
|
|
48
33
|
}
|
|
49
34
|
async sendSignInLink(opts) {
|
|
50
35
|
return await this.users.sendSignInLink({
|
|
51
|
-
base_url: this.base_url,
|
|
52
36
|
email: opts.email,
|
|
53
37
|
});
|
|
54
38
|
}
|
|
55
39
|
async resolveUsername(opts) {
|
|
56
40
|
const username = normalizeUsername(opts.username);
|
|
57
41
|
const out = await this.users.resolveUsername({
|
|
58
|
-
base_url: this.base_url,
|
|
59
42
|
username,
|
|
60
43
|
});
|
|
61
44
|
if (out.value === undefined) {
|
|
62
|
-
throw
|
|
45
|
+
throw errUsernameResolveFailed();
|
|
63
46
|
}
|
|
64
47
|
return out.value;
|
|
65
48
|
}
|
|
66
49
|
async verifyUsername(opts) {
|
|
67
50
|
const check = validateUsernameFormat(opts.to_validate);
|
|
68
51
|
if (!check.valid) {
|
|
69
|
-
throw
|
|
52
|
+
throw errUsernameInvalid(check.error);
|
|
70
53
|
}
|
|
71
54
|
return await this.tmp_usernames.verify({
|
|
72
|
-
base_url: this.base_url,
|
|
73
55
|
words: opts.words,
|
|
74
56
|
to_validate: check.normalized,
|
|
75
57
|
});
|
|
76
58
|
}
|
|
77
59
|
async generateUsernames(opts) {
|
|
78
60
|
return await this.tmp_usernames.verify({
|
|
79
|
-
base_url: this.base_url,
|
|
80
61
|
words: opts.words,
|
|
81
62
|
to_validate: "",
|
|
82
63
|
});
|
|
@@ -84,10 +65,9 @@ export class UsersFX {
|
|
|
84
65
|
async sendPhoneCode(opts) {
|
|
85
66
|
const phone = normalizePhone(opts.phone);
|
|
86
67
|
if (!validatePhone(phone)) {
|
|
87
|
-
throw
|
|
68
|
+
throw errPhoneRequired();
|
|
88
69
|
}
|
|
89
70
|
return await this.tmp_phones.send({
|
|
90
|
-
base_url: this.base_url,
|
|
91
71
|
phone,
|
|
92
72
|
});
|
|
93
73
|
}
|
|
@@ -95,39 +75,29 @@ export class UsersFX {
|
|
|
95
75
|
const phone = normalizePhone(opts.phone);
|
|
96
76
|
const code = normalizePhoneCode(opts.code);
|
|
97
77
|
if (!validatePhone(phone)) {
|
|
98
|
-
throw
|
|
78
|
+
throw errPhoneRequired();
|
|
99
79
|
}
|
|
100
80
|
if (!validatePhoneCode(code)) {
|
|
101
|
-
throw
|
|
81
|
+
throw errPhoneCodeRequired();
|
|
102
82
|
}
|
|
103
83
|
return await this.tmp_phones.verify({
|
|
104
|
-
base_url: this.base_url,
|
|
105
84
|
phone,
|
|
106
85
|
code,
|
|
107
86
|
});
|
|
108
87
|
}
|
|
109
88
|
async match(opts) {
|
|
110
|
-
const token = await this.auth.getToken();
|
|
111
89
|
return await this.users.match({
|
|
112
|
-
base_url: this.base_url,
|
|
113
|
-
token,
|
|
114
90
|
contacts: opts.contacts,
|
|
115
91
|
});
|
|
116
92
|
}
|
|
117
93
|
async search(opts) {
|
|
118
|
-
const token = await this.auth.getToken();
|
|
119
94
|
return await this.users.search({
|
|
120
|
-
base_url: this.base_url,
|
|
121
|
-
token,
|
|
122
95
|
q: opts.q,
|
|
123
96
|
limit: opts.limit,
|
|
124
97
|
});
|
|
125
98
|
}
|
|
126
99
|
async getByUID(opts) {
|
|
127
|
-
const token = await this.auth.getToken();
|
|
128
100
|
return await this.users.getByUID({
|
|
129
|
-
base_url: this.base_url,
|
|
130
|
-
token,
|
|
131
101
|
uid: opts.uid,
|
|
132
102
|
});
|
|
133
103
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabriktor/fx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"typescript": "^6.0.3"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@fabriktor/client": "^0.0.
|
|
20
|
+
"@fabriktor/client": "^0.0.16",
|
|
21
21
|
"@fabriktor/schema": "^0.0.12"
|
|
22
22
|
}
|
|
23
23
|
}
|