@passlock/node 2.0.7 → 2.1.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/index.d.ts +1 -114
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -108
- package/dist/index.js.map +1 -1
- package/dist/safe.d.ts +1 -153
- package/dist/safe.d.ts.map +1 -1
- package/dist/safe.js +8 -146
- package/dist/safe.js.map +1 -1
- package/package.json +9 -14
- package/dist/effect.d.ts +0 -7
- package/dist/effect.d.ts.map +0 -1
- package/dist/effect.js +0 -4
- package/dist/effect.js.map +0 -1
- package/dist/errors.d.ts +0 -71
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -30
- package/dist/errors.js.map +0 -1
- package/dist/network.d.ts +0 -134
- package/dist/network.d.ts.map +0 -1
- package/dist/network.js +0 -172
- package/dist/network.js.map +0 -1
- package/dist/passkey/passkey.d.ts +0 -132
- package/dist/passkey/passkey.d.ts.map +0 -1
- package/dist/passkey/passkey.js +0 -158
- package/dist/passkey/passkey.js.map +0 -1
- package/dist/principal/principal.d.ts +0 -22
- package/dist/principal/principal.d.ts.map +0 -1
- package/dist/principal/principal.js +0 -65
- package/dist/principal/principal.js.map +0 -1
- package/dist/schemas/errors.d.ts +0 -2
- package/dist/schemas/errors.d.ts.map +0 -1
- package/dist/schemas/errors.js +0 -72
- package/dist/schemas/errors.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -5
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -5
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/passkey.d.ts +0 -85
- package/dist/schemas/passkey.d.ts.map +0 -1
- package/dist/schemas/passkey.js +0 -64
- package/dist/schemas/passkey.js.map +0 -1
- package/dist/schemas/principal.d.ts +0 -88
- package/dist/schemas/principal.d.ts.map +0 -1
- package/dist/schemas/principal.js +0 -46
- package/dist/schemas/principal.js.map +0 -1
- package/dist/schemas/satisfy.d.ts +0 -2
- package/dist/schemas/satisfy.d.ts.map +0 -1
- package/dist/schemas/satisfy.js +0 -2
- package/dist/schemas/satisfy.js.map +0 -1
- package/dist/schemas/signup.d.ts +0 -13
- package/dist/schemas/signup.d.ts.map +0 -1
- package/dist/schemas/signup.js +0 -11
- package/dist/schemas/signup.js.map +0 -1
- package/dist/shared.d.ts +0 -19
- package/dist/shared.d.ts.map +0 -1
- package/dist/shared.js +0 -9
- package/dist/shared.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@passlock/node",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Passkey authentication for NodeJS backends",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"passkey",
|
|
@@ -33,11 +33,6 @@
|
|
|
33
33
|
"types": "./dist/safe.d.ts",
|
|
34
34
|
"import": "./dist/safe.js",
|
|
35
35
|
"default": "./dist/safe.js"
|
|
36
|
-
},
|
|
37
|
-
"./effect": {
|
|
38
|
-
"types": "./dist/effect.d.ts",
|
|
39
|
-
"import": "./dist/effect.js",
|
|
40
|
-
"default": "./dist/effect.js"
|
|
41
36
|
}
|
|
42
37
|
},
|
|
43
38
|
"module": "./dist/index.js",
|
|
@@ -48,20 +43,20 @@
|
|
|
48
43
|
"!dist/**/*.spec.*"
|
|
49
44
|
],
|
|
50
45
|
"dependencies": {
|
|
51
|
-
"effect": "3.
|
|
52
|
-
"jose": "^6.2.
|
|
46
|
+
"effect": "3.21.0",
|
|
47
|
+
"jose": "^6.2.2"
|
|
53
48
|
},
|
|
54
49
|
"devDependencies": {
|
|
55
|
-
"@biomejs/biome": "^2.4.
|
|
56
|
-
"@effect/vitest": "^0.
|
|
57
|
-
"@types/node": "25.
|
|
50
|
+
"@biomejs/biome": "^2.4.10",
|
|
51
|
+
"@effect/vitest": "^0.29.0",
|
|
52
|
+
"@types/node": "25.5.2",
|
|
58
53
|
"globals": "^17.4.0",
|
|
59
|
-
"npm-check-updates": "^
|
|
54
|
+
"npm-check-updates": "^20.0.0",
|
|
60
55
|
"publint": "0.3.18",
|
|
61
56
|
"rimraf": "^6.1.3",
|
|
62
57
|
"tsx": "4.21.0",
|
|
63
|
-
"typedoc": "^0.28.
|
|
64
|
-
"typescript": "^
|
|
58
|
+
"typedoc": "^0.28.18",
|
|
59
|
+
"typescript": "^6.0.2",
|
|
65
60
|
"vite-tsconfig-paths": "^6.1.1",
|
|
66
61
|
"vitest": "^3.2.4"
|
|
67
62
|
},
|
package/dist/effect.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export type { AssignUserOptions, ListPasskeyOptions, } from "./passkey/passkey.js";
|
|
2
|
-
export { assignUser, deletePasskey, getPasskey, listPasskeys, } from "./passkey/passkey.js";
|
|
3
|
-
export type {} from "./principal/principal.js";
|
|
4
|
-
export { exchangeCode, VerificationError, verifyIdToken, } from "./principal/principal.js";
|
|
5
|
-
export * from "./schemas/index.js";
|
|
6
|
-
export type { AuthenticatedOptions, PasslockOptions, } from "./shared.js";
|
|
7
|
-
//# sourceMappingURL=effect.d.ts.map
|
package/dist/effect.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,UAAU,EACV,aAAa,EACb,UAAU,EACV,YAAY,GACb,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC9C,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,aAAa,GACd,MAAM,0BAA0B,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,YAAY,EACV,oBAAoB,EACpB,eAAe,GAChB,MAAM,aAAa,CAAA"}
|
package/dist/effect.js
DELETED
package/dist/effect.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,UAAU,EACV,aAAa,EACb,UAAU,EACV,YAAY,GACb,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,aAAa,GACd,MAAM,0BAA0B,CAAA;AACjC,cAAc,oBAAoB,CAAA","sourcesContent":["export type {\n AssignUserOptions,\n ListPasskeyOptions,\n} from \"./passkey/passkey.js\"\nexport {\n assignUser,\n deletePasskey,\n getPasskey,\n listPasskeys,\n} from \"./passkey/passkey.js\"\nexport type {} from \"./principal/principal.js\"\nexport {\n exchangeCode,\n VerificationError,\n verifyIdToken,\n} from \"./principal/principal.js\"\nexport * from \"./schemas/index.js\"\nexport type {\n AuthenticatedOptions,\n PasslockOptions,\n} from \"./shared.js\"\n"]}
|
package/dist/errors.d.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @category Authentication
|
|
3
|
-
*/
|
|
4
|
-
export type UnauthorizedError = {
|
|
5
|
-
_tag: "@error/Unauthorized";
|
|
6
|
-
message: string;
|
|
7
|
-
};
|
|
8
|
-
export declare const isUnauthorizedError: (payload: unknown) => payload is UnauthorizedError;
|
|
9
|
-
/**
|
|
10
|
-
* @category Authentication
|
|
11
|
-
*/
|
|
12
|
-
export type ForbiddenError = {
|
|
13
|
-
_tag: "@error/Forbidden";
|
|
14
|
-
message: string;
|
|
15
|
-
};
|
|
16
|
-
export declare const isForbiddenError: (payload: unknown) => payload is ForbiddenError;
|
|
17
|
-
/**
|
|
18
|
-
* @category Principal
|
|
19
|
-
*/
|
|
20
|
-
export type InvalidCodeError = {
|
|
21
|
-
_tag: "@error/InvalidCode";
|
|
22
|
-
message: string;
|
|
23
|
-
};
|
|
24
|
-
export declare const isInvalidCodeError: (payload: unknown) => payload is InvalidCodeError;
|
|
25
|
-
/**
|
|
26
|
-
* @category Principal
|
|
27
|
-
*/
|
|
28
|
-
export type VerificationError = {
|
|
29
|
-
_tag: "@error/Verification";
|
|
30
|
-
message: string;
|
|
31
|
-
};
|
|
32
|
-
export declare const isVerificationError: (payload: unknown) => payload is VerificationError;
|
|
33
|
-
export type InvalidTenancyError = {
|
|
34
|
-
_tag: "@error/InvalidTenancy";
|
|
35
|
-
message: string;
|
|
36
|
-
};
|
|
37
|
-
export declare const isInvalidTenancyError: (payload: unknown) => payload is InvalidTenancyError;
|
|
38
|
-
/**
|
|
39
|
-
* Error payload returned when a passkey cannot be found for a given
|
|
40
|
-
* authentication attempt.
|
|
41
|
-
*
|
|
42
|
-
* @category Passkeys
|
|
43
|
-
*/
|
|
44
|
-
export type PasskeyNotFoundError = {
|
|
45
|
-
_tag: "@error/PasskeyNotFound";
|
|
46
|
-
message: string;
|
|
47
|
-
credentialId: string;
|
|
48
|
-
rpId: string;
|
|
49
|
-
};
|
|
50
|
-
export declare const isPasskeyNotFoundError: (payload: unknown) => payload is PasskeyNotFoundError;
|
|
51
|
-
export type NotFoundError = {
|
|
52
|
-
_tag: "@error/NotFound";
|
|
53
|
-
message: string;
|
|
54
|
-
};
|
|
55
|
-
export declare const isNotFoundError: (payload: unknown) => payload is NotFoundError;
|
|
56
|
-
export type InvalidEmailError = {
|
|
57
|
-
_tag: "@error/InvalidEmail";
|
|
58
|
-
message: string;
|
|
59
|
-
};
|
|
60
|
-
export declare const isInvalidEmailError: (payload: unknown) => payload is InvalidEmailError;
|
|
61
|
-
export type DuplicateEmailError = {
|
|
62
|
-
_tag: "@error/DuplicateEmail";
|
|
63
|
-
message: string;
|
|
64
|
-
};
|
|
65
|
-
export declare const isDuplicateEmailError: (payload: unknown) => payload is DuplicateEmailError;
|
|
66
|
-
export type BadRequestError = {
|
|
67
|
-
_tag: "@error/BadRequest";
|
|
68
|
-
message: string;
|
|
69
|
-
};
|
|
70
|
-
export declare const isBadRequestError: (payload: unknown) => payload is BadRequestError;
|
|
71
|
-
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,qBAAqB,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,eAAO,MAAM,mBAAmB,YArBpB,OAAO,KAAG,OAAO,qBAuB5B,CAAA;AAID;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,kBAAkB,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,eAAO,MAAM,gBAAgB,YAnCjB,OAAO,KAAG,OAAO,kBAmC+C,CAAA;AAI5E;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,oBAAoB,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,eAAO,MAAM,kBAAkB,YA/CnB,OAAO,KAAG,OAAO,oBAgDqB,CAAA;AAIlD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,qBAAqB,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,eAAO,MAAM,mBAAmB,YA5DpB,OAAO,KAAG,OAAO,qBA8D5B,CAAA;AAID,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,uBAAuB,CAAA;IAC7B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,eAAO,MAAM,qBAAqB,YAvEtB,OAAO,KAAG,OAAO,uBAyE5B,CAAA;AAID;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,wBAAwB,CAAA;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,eAAO,MAAM,sBAAsB,YA1FvB,OAAO,KAAG,OAAO,wBA4F5B,CAAA;AAID,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,iBAAiB,CAAA;IACvB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,eAAO,MAAM,eAAe,YArGhB,OAAO,KAAG,OAAO,iBAqG4C,CAAA;AAIzE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,qBAAqB,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,eAAO,MAAM,mBAAmB,YA9GpB,OAAO,KAAG,OAAO,qBAgH5B,CAAA;AAID,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,uBAAuB,CAAA;IAC7B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,eAAO,MAAM,qBAAqB,YAzHtB,OAAO,KAAG,OAAO,uBA2H5B,CAAA;AAID,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,mBAAmB,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,eAAO,MAAM,iBAAiB,YApIlB,OAAO,KAAG,OAAO,mBAoIkD,CAAA"}
|
package/dist/errors.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Publicly exposed errors.
|
|
3
|
-
* The errors we receive from the API live in the schemas/errors.ts module.
|
|
4
|
-
* The errors here have the same shape but they are simple types
|
|
5
|
-
* so are easier for non Effect consumers to handle.
|
|
6
|
-
*/
|
|
7
|
-
const isTagged = (tag) => (payload) => {
|
|
8
|
-
if (typeof payload !== "object")
|
|
9
|
-
return false;
|
|
10
|
-
if (payload === null)
|
|
11
|
-
return false;
|
|
12
|
-
if (!("_tag" in payload))
|
|
13
|
-
return false;
|
|
14
|
-
if (typeof payload._tag !== "string")
|
|
15
|
-
return false;
|
|
16
|
-
if (payload._tag !== tag)
|
|
17
|
-
return false;
|
|
18
|
-
return true;
|
|
19
|
-
};
|
|
20
|
-
export const isUnauthorizedError = isTagged("@error/Unauthorized");
|
|
21
|
-
export const isForbiddenError = isTagged("@error/Forbidden");
|
|
22
|
-
export const isInvalidCodeError = isTagged("@error/InvalidCode");
|
|
23
|
-
export const isVerificationError = isTagged("@error/Verification");
|
|
24
|
-
export const isInvalidTenancyError = isTagged("@error/InvalidTenancy");
|
|
25
|
-
export const isPasskeyNotFoundError = isTagged("@error/PasskeyNotFound");
|
|
26
|
-
export const isNotFoundError = isTagged("@error/NotFound");
|
|
27
|
-
export const isInvalidEmailError = isTagged("@error/InvalidEmail");
|
|
28
|
-
export const isDuplicateEmailError = isTagged("@error/DuplicateEmail");
|
|
29
|
-
export const isBadRequestError = isTagged("@error/BadRequest");
|
|
30
|
-
//# sourceMappingURL=errors.js.map
|
package/dist/errors.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,QAAQ,GACZ,CAA6B,GAAc,EAAE,EAAE,CAC/C,CAAC,OAAgB,EAAgB,EAAE;IACjC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC7C,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAElC,IAAI,CAAC,CAAC,MAAM,IAAI,OAAO,CAAC;QAAE,OAAO,KAAK,CAAA;IACtC,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAClD,IAAI,OAAO,CAAC,IAAI,KAAK,GAAG;QAAE,OAAO,KAAK,CAAA;IAEtC,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAYH,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CACzC,qBAAqB,CACtB,CAAA;AAYD,MAAM,CAAC,MAAM,gBAAgB,GAAG,QAAQ,CAAiB,kBAAkB,CAAC,CAAA;AAY5E,MAAM,CAAC,MAAM,kBAAkB,GAC7B,QAAQ,CAAmB,oBAAoB,CAAC,CAAA;AAYlD,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CACzC,qBAAqB,CACtB,CAAA;AASD,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAC3C,uBAAuB,CACxB,CAAA;AAiBD,MAAM,CAAC,MAAM,sBAAsB,GAAG,QAAQ,CAC5C,wBAAwB,CACzB,CAAA;AASD,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAgB,iBAAiB,CAAC,CAAA;AASzE,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CACzC,qBAAqB,CACtB,CAAA;AASD,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAC3C,uBAAuB,CACxB,CAAA;AASD,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAkB,mBAAmB,CAAC,CAAA","sourcesContent":["/*\n * Publicly exposed errors.\n * The errors we receive from the API live in the schemas/errors.ts module.\n * The errors here have the same shape but they are simple types\n * so are easier for non Effect consumers to handle.\n */\n\nconst isTagged =\n <A extends { _tag: string }>(tag: A[\"_tag\"]) =>\n (payload: unknown): payload is A => {\n if (typeof payload !== \"object\") return false\n if (payload === null) return false\n\n if (!(\"_tag\" in payload)) return false\n if (typeof payload._tag !== \"string\") return false\n if (payload._tag !== tag) return false\n\n return true\n }\n\n/* Unauthorized */\n\n/**\n * @category Authentication\n */\nexport type UnauthorizedError = {\n _tag: \"@error/Unauthorized\"\n message: string\n}\n\nexport const isUnauthorizedError = isTagged<UnauthorizedError>(\n \"@error/Unauthorized\"\n)\n\n/* Forbidden */\n\n/**\n * @category Authentication\n */\nexport type ForbiddenError = {\n _tag: \"@error/Forbidden\"\n message: string\n}\n\nexport const isForbiddenError = isTagged<ForbiddenError>(\"@error/Forbidden\")\n\n/* InvalidCode */\n\n/**\n * @category Principal\n */\nexport type InvalidCodeError = {\n _tag: \"@error/InvalidCode\"\n message: string\n}\n\nexport const isInvalidCodeError =\n isTagged<InvalidCodeError>(\"@error/InvalidCode\")\n\n/* VerificationFailure */\n\n/**\n * @category Principal\n */\nexport type VerificationError = {\n _tag: \"@error/Verification\"\n message: string\n}\n\nexport const isVerificationError = isTagged<VerificationError>(\n \"@error/Verification\"\n)\n\n/* InvalidTenancy */\n\nexport type InvalidTenancyError = {\n _tag: \"@error/InvalidTenancy\"\n message: string\n}\n\nexport const isInvalidTenancyError = isTagged<InvalidTenancyError>(\n \"@error/InvalidTenancy\"\n)\n\n/* PasskeyNotFound */\n\n/**\n * Error payload returned when a passkey cannot be found for a given\n * authentication attempt.\n *\n * @category Passkeys\n */\nexport type PasskeyNotFoundError = {\n _tag: \"@error/PasskeyNotFound\"\n message: string\n credentialId: string\n rpId: string\n}\n\nexport const isPasskeyNotFoundError = isTagged<PasskeyNotFoundError>(\n \"@error/PasskeyNotFound\"\n)\n\n/* NotFound */\n\nexport type NotFoundError = {\n _tag: \"@error/NotFound\"\n message: string\n}\n\nexport const isNotFoundError = isTagged<NotFoundError>(\"@error/NotFound\")\n\n/* InvalidEmail */\n\nexport type InvalidEmailError = {\n _tag: \"@error/InvalidEmail\"\n message: string\n}\n\nexport const isInvalidEmailError = isTagged<InvalidEmailError>(\n \"@error/InvalidEmail\"\n)\n\n/* DuplicateEmail */\n\nexport type DuplicateEmailError = {\n _tag: \"@error/DuplicateEmail\"\n message: string\n}\n\nexport const isDuplicateEmailError = isTagged<DuplicateEmailError>(\n \"@error/DuplicateEmail\"\n)\n\n/* BadRequest */\n\nexport type BadRequestError = {\n _tag: \"@error/BadRequest\"\n message: string\n}\n\nexport const isBadRequestError = isTagged<BadRequestError>(\"@error/BadRequest\")\n"]}
|
package/dist/network.d.ts
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { Context, Effect, Layer } from "effect";
|
|
2
|
-
/**
|
|
3
|
-
* Supported HTTP methods accepted by {@link fetchNetwork}.
|
|
4
|
-
*/
|
|
5
|
-
export type NetworkMethod = "get" | "post" | "delete" | "patch";
|
|
6
|
-
/**
|
|
7
|
-
* Lightweight response model used by this package.
|
|
8
|
-
*
|
|
9
|
-
* Invariants:
|
|
10
|
-
* - `json` is lazy: parsing only happens when the effect is run.
|
|
11
|
-
* - `json` is memoized per response wrapper, so repeated evaluation does not
|
|
12
|
-
* parse the same payload multiple times.
|
|
13
|
-
*/
|
|
14
|
-
export interface NetworkResponse {
|
|
15
|
-
readonly status: number;
|
|
16
|
-
readonly statusText: string;
|
|
17
|
-
readonly statusMessage: string;
|
|
18
|
-
readonly headers: Readonly<Record<string, string>>;
|
|
19
|
-
readonly json: Effect.Effect<unknown, NetworkResponseError>;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Accepted request header input formats.
|
|
23
|
-
*/
|
|
24
|
-
export type NetworkHeaders = Headers | Readonly<Record<string, string>> | Array<[string, string]>;
|
|
25
|
-
/**
|
|
26
|
-
* Optional request options for {@link fetchNetwork}.
|
|
27
|
-
*/
|
|
28
|
-
export interface FetchNetworkOptions {
|
|
29
|
-
readonly headers?: NetworkHeaders;
|
|
30
|
-
}
|
|
31
|
-
declare const NetworkFetch_base: Context.TagClass<NetworkFetch, "@passlock/node/network/Fetch", typeof fetch>;
|
|
32
|
-
/**
|
|
33
|
-
* Effect service tag for the fetch implementation.
|
|
34
|
-
*
|
|
35
|
-
* Supply this service with `Effect.provide` / layers to swap fetch behavior
|
|
36
|
-
* in tests or alternate runtimes.
|
|
37
|
-
*/
|
|
38
|
-
export declare class NetworkFetch extends NetworkFetch_base {
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Default live fetch layer backed by `globalThis.fetch`.
|
|
42
|
-
*/
|
|
43
|
-
export declare const NetworkFetchLive: Layer.Layer<NetworkFetch>;
|
|
44
|
-
/**
|
|
45
|
-
* HTTP status buckets used by {@link matchStatus}.
|
|
46
|
-
*/
|
|
47
|
-
export type NetworkResponseStatusCase = "2xx" | "3xx" | "4xx" | "5xx";
|
|
48
|
-
type MatchStatusHandler<Resp extends NetworkResponse = NetworkResponse, A = unknown, E = unknown> = (response: Resp) => Effect.Effect<A, E, never>;
|
|
49
|
-
type HandlerEffect<Cases extends MatchStatusCases<Resp>, Resp extends NetworkResponse, Case extends NetworkResponseStatusCase | "orElse"> = Case extends keyof Cases ? NonNullable<Cases[Case]> extends MatchStatusHandler<Resp> ? ReturnType<NonNullable<Cases[Case]>> : never : never;
|
|
50
|
-
type MatchStatusEffectUnion<Cases extends MatchStatusCases<Resp>, Resp extends NetworkResponse> = HandlerEffect<Cases, Resp, "2xx"> | HandlerEffect<Cases, Resp, "3xx"> | HandlerEffect<Cases, Resp, "4xx"> | HandlerEffect<Cases, Resp, "5xx"> | HandlerEffect<Cases, Resp, "orElse">;
|
|
51
|
-
type EffectSuccess<T> = T extends Effect.Effect<infer A, unknown, unknown> ? A : never;
|
|
52
|
-
type EffectError<T> = T extends Effect.Effect<unknown, infer E, unknown> ? E : never;
|
|
53
|
-
type EffectContext<T> = T extends Effect.Effect<unknown, unknown, infer R> ? R : never;
|
|
54
|
-
/**
|
|
55
|
-
* Handlers used by {@link matchStatus}.
|
|
56
|
-
*
|
|
57
|
-
* Invariants:
|
|
58
|
-
* - `orElse` is always required.
|
|
59
|
-
* - Specific status family handlers are optional and fall back to `orElse`
|
|
60
|
-
* when missing.
|
|
61
|
-
*/
|
|
62
|
-
export interface MatchStatusCases<Resp extends NetworkResponse = NetworkResponse> {
|
|
63
|
-
readonly "2xx"?: MatchStatusHandler<Resp>;
|
|
64
|
-
readonly "3xx"?: MatchStatusHandler<Resp>;
|
|
65
|
-
readonly "4xx"?: MatchStatusHandler<Resp>;
|
|
66
|
-
readonly "5xx"?: MatchStatusHandler<Resp>;
|
|
67
|
-
readonly orElse: MatchStatusHandler<Resp>;
|
|
68
|
-
}
|
|
69
|
-
declare const NetworkRequestError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
70
|
-
readonly _tag: "@error/NetworkRequest";
|
|
71
|
-
} & Readonly<A>;
|
|
72
|
-
/**
|
|
73
|
-
* Raised when the underlying fetch call fails before a response is received.
|
|
74
|
-
*/
|
|
75
|
-
export declare class NetworkRequestError extends NetworkRequestError_base<{
|
|
76
|
-
readonly method: NetworkMethod;
|
|
77
|
-
readonly url: string;
|
|
78
|
-
readonly message: string;
|
|
79
|
-
}> {
|
|
80
|
-
}
|
|
81
|
-
declare const NetworkPayloadError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
82
|
-
readonly _tag: "@error/NetworkPayload";
|
|
83
|
-
} & Readonly<A>;
|
|
84
|
-
/**
|
|
85
|
-
* Raised when request payload serialization fails.
|
|
86
|
-
*/
|
|
87
|
-
export declare class NetworkPayloadError extends NetworkPayloadError_base<{
|
|
88
|
-
readonly method: NetworkMethod;
|
|
89
|
-
readonly message: string;
|
|
90
|
-
}> {
|
|
91
|
-
}
|
|
92
|
-
declare const NetworkResponseError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
93
|
-
readonly _tag: "@error/NetworkResponse";
|
|
94
|
-
} & Readonly<A>;
|
|
95
|
-
/**
|
|
96
|
-
* Raised when response body parsing fails.
|
|
97
|
-
*/
|
|
98
|
-
export declare class NetworkResponseError extends NetworkResponseError_base<{
|
|
99
|
-
readonly method: NetworkMethod;
|
|
100
|
-
readonly url: string;
|
|
101
|
-
readonly message: string;
|
|
102
|
-
}> {
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Convert an HTTP status code into its status family bucket.
|
|
106
|
-
*
|
|
107
|
-
* Returns `undefined` for codes outside the 2xx-5xx families.
|
|
108
|
-
*/
|
|
109
|
-
export declare const statusToCase: (status: number) => NetworkResponseStatusCase | undefined;
|
|
110
|
-
/**
|
|
111
|
-
* Route a {@link NetworkResponse} to the first matching status-family handler.
|
|
112
|
-
*
|
|
113
|
-
* Invariants:
|
|
114
|
-
* - `2xx`/`3xx`/`4xx`/`5xx` handlers are matched by status family.
|
|
115
|
-
* - `orElse` is always used as a fallback when no specific family handler exists.
|
|
116
|
-
* - The returned effect type is inferred as the union of all handler effects.
|
|
117
|
-
*/
|
|
118
|
-
export declare const matchStatus: <Resp extends NetworkResponse, Cases extends MatchStatusCases<Resp>>(response: Resp, cases: Cases) => Effect.Effect<EffectSuccess<MatchStatusEffectUnion<Cases, Resp>>, EffectError<MatchStatusEffectUnion<Cases, Resp>>, EffectContext<MatchStatusEffectUnion<Cases, Resp>>>;
|
|
119
|
-
/**
|
|
120
|
-
* Convert `Headers` into a readonly plain record.
|
|
121
|
-
*/
|
|
122
|
-
export declare const headersToRecord: (headers: Headers) => Readonly<Record<string, string>>;
|
|
123
|
-
/**
|
|
124
|
-
* Execute a fetch request using the injected {@link NetworkFetch} service.
|
|
125
|
-
*
|
|
126
|
-
* Invariants:
|
|
127
|
-
* - method is always normalized to upper-case before dispatch.
|
|
128
|
-
* - JSON payload (if present) is serialized before request execution.
|
|
129
|
-
* - caller headers override payload-derived headers when keys overlap.
|
|
130
|
-
* - the returned `NetworkResponse.json` remains lazy.
|
|
131
|
-
*/
|
|
132
|
-
export declare const fetchNetwork: (url: string | URL, method: NetworkMethod, payload?: unknown, options?: FetchNetworkOptions) => Effect.Effect<NetworkResponse, NetworkRequestError | NetworkPayloadError, NetworkFetch>;
|
|
133
|
-
export {};
|
|
134
|
-
//# sourceMappingURL=network.d.ts.map
|
package/dist/network.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"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"}
|
package/dist/network.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { Context, Data, Effect, Layer } from "effect";
|
|
2
|
-
/**
|
|
3
|
-
* Effect service tag for the fetch implementation.
|
|
4
|
-
*
|
|
5
|
-
* Supply this service with `Effect.provide` / layers to swap fetch behavior
|
|
6
|
-
* in tests or alternate runtimes.
|
|
7
|
-
*/
|
|
8
|
-
export class NetworkFetch extends Context.Tag("@passlock/node/network/Fetch")() {
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Default live fetch layer backed by `globalThis.fetch`.
|
|
12
|
-
*/
|
|
13
|
-
export const NetworkFetchLive = Layer.succeed(NetworkFetch, globalThis.fetch);
|
|
14
|
-
/**
|
|
15
|
-
* Raised when the underlying fetch call fails before a response is received.
|
|
16
|
-
*/
|
|
17
|
-
export class NetworkRequestError extends Data.TaggedError("@error/NetworkRequest") {
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Raised when request payload serialization fails.
|
|
21
|
-
*/
|
|
22
|
-
export class NetworkPayloadError extends Data.TaggedError("@error/NetworkPayload") {
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Raised when response body parsing fails.
|
|
26
|
-
*/
|
|
27
|
-
export class NetworkResponseError extends Data.TaggedError("@error/NetworkResponse") {
|
|
28
|
-
}
|
|
29
|
-
const formatMessage = (cause, fallback) => cause instanceof Error ? cause.message : fallback;
|
|
30
|
-
/**
|
|
31
|
-
* Convert an HTTP status code into its status family bucket.
|
|
32
|
-
*
|
|
33
|
-
* Returns `undefined` for codes outside the 2xx-5xx families.
|
|
34
|
-
*/
|
|
35
|
-
export const statusToCase = (status) => {
|
|
36
|
-
if (status >= 200 && status <= 299)
|
|
37
|
-
return "2xx";
|
|
38
|
-
if (status >= 300 && status <= 399)
|
|
39
|
-
return "3xx";
|
|
40
|
-
if (status >= 400 && status <= 499)
|
|
41
|
-
return "4xx";
|
|
42
|
-
if (status >= 500 && status <= 599)
|
|
43
|
-
return "5xx";
|
|
44
|
-
return undefined;
|
|
45
|
-
};
|
|
46
|
-
const resolveStatusHandler = (response, cases) => {
|
|
47
|
-
const statusCase = statusToCase(response.status);
|
|
48
|
-
if (!statusCase)
|
|
49
|
-
return cases.orElse;
|
|
50
|
-
const handler = cases[statusCase];
|
|
51
|
-
return (handler ?? cases.orElse);
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* Route a {@link NetworkResponse} to the first matching status-family handler.
|
|
55
|
-
*
|
|
56
|
-
* Invariants:
|
|
57
|
-
* - `2xx`/`3xx`/`4xx`/`5xx` handlers are matched by status family.
|
|
58
|
-
* - `orElse` is always used as a fallback when no specific family handler exists.
|
|
59
|
-
* - The returned effect type is inferred as the union of all handler effects.
|
|
60
|
-
*/
|
|
61
|
-
export const matchStatus = (response, cases) => Effect.suspend(() => {
|
|
62
|
-
const handler = resolveStatusHandler(response, cases);
|
|
63
|
-
return handler(response);
|
|
64
|
-
});
|
|
65
|
-
/**
|
|
66
|
-
* Serialize an optional payload into a JSON request body.
|
|
67
|
-
*
|
|
68
|
-
* Invariants:
|
|
69
|
-
* - `GET` requests cannot carry a payload and fail with `NetworkPayloadError`.
|
|
70
|
-
* - when a payload exists, `content-type: application/json` is emitted.
|
|
71
|
-
*/
|
|
72
|
-
const serializePayload = (method, payload) => {
|
|
73
|
-
if (payload === undefined) {
|
|
74
|
-
return Effect.succeed(undefined);
|
|
75
|
-
}
|
|
76
|
-
if (method === "get") {
|
|
77
|
-
return Effect.fail(new NetworkPayloadError({
|
|
78
|
-
method,
|
|
79
|
-
message: "GET requests do not support a request body",
|
|
80
|
-
}));
|
|
81
|
-
}
|
|
82
|
-
return Effect.try({
|
|
83
|
-
try: () => ({
|
|
84
|
-
body: JSON.stringify(payload),
|
|
85
|
-
headers: { "content-type": "application/json" },
|
|
86
|
-
}),
|
|
87
|
-
catch: (cause) => new NetworkPayloadError({
|
|
88
|
-
method,
|
|
89
|
-
message: formatMessage(cause, "Unable to serialize payload to JSON"),
|
|
90
|
-
}),
|
|
91
|
-
});
|
|
92
|
-
};
|
|
93
|
-
/**
|
|
94
|
-
* Convert `Headers` into a readonly plain record.
|
|
95
|
-
*/
|
|
96
|
-
export const headersToRecord = (headers) => Object.fromEntries(headers.entries());
|
|
97
|
-
const normalizeHeaders = (headers) => {
|
|
98
|
-
if (headers instanceof Headers) {
|
|
99
|
-
return new Headers(headers);
|
|
100
|
-
}
|
|
101
|
-
if (Array.isArray(headers)) {
|
|
102
|
-
return new Headers(headers);
|
|
103
|
-
}
|
|
104
|
-
return new Headers(headers);
|
|
105
|
-
};
|
|
106
|
-
const mergeHeaders = (...headers) => Object.assign({}, ...headers);
|
|
107
|
-
/**
|
|
108
|
-
* Build a lazy, memoized JSON parser effect from a response.
|
|
109
|
-
*
|
|
110
|
-
* Invariants:
|
|
111
|
-
* - parsing happens on effect execution, not during response construction.
|
|
112
|
-
* - parsing uses `response.clone()` so the original response body remains untouched.
|
|
113
|
-
*/
|
|
114
|
-
const makeJsonEffect = (response, context) => {
|
|
115
|
-
let cached;
|
|
116
|
-
return Effect.tryPromise({
|
|
117
|
-
try: () => {
|
|
118
|
-
cached = cached ?? response.clone().json();
|
|
119
|
-
return cached;
|
|
120
|
-
},
|
|
121
|
-
catch: (cause) => new NetworkResponseError({
|
|
122
|
-
method: context.method,
|
|
123
|
-
url: context.url,
|
|
124
|
-
message: formatMessage(cause, "Unable to parse response JSON"),
|
|
125
|
-
}),
|
|
126
|
-
});
|
|
127
|
-
};
|
|
128
|
-
const toNetworkResponse = (response, context) => ({
|
|
129
|
-
status: response.status,
|
|
130
|
-
statusText: response.statusText,
|
|
131
|
-
statusMessage: response.statusText,
|
|
132
|
-
headers: headersToRecord(response.headers),
|
|
133
|
-
json: makeJsonEffect(response, context),
|
|
134
|
-
});
|
|
135
|
-
/**
|
|
136
|
-
* Execute a fetch request using the injected {@link NetworkFetch} service.
|
|
137
|
-
*
|
|
138
|
-
* Invariants:
|
|
139
|
-
* - method is always normalized to upper-case before dispatch.
|
|
140
|
-
* - JSON payload (if present) is serialized before request execution.
|
|
141
|
-
* - caller headers override payload-derived headers when keys overlap.
|
|
142
|
-
* - the returned `NetworkResponse.json` remains lazy.
|
|
143
|
-
*/
|
|
144
|
-
export const fetchNetwork = (url, method, payload, options) => Effect.gen(function* () {
|
|
145
|
-
const requestUrl = String(url);
|
|
146
|
-
const context = { method, url: requestUrl };
|
|
147
|
-
const fetchImpl = yield* NetworkFetch;
|
|
148
|
-
const serialized = yield* serializePayload(method, payload);
|
|
149
|
-
const providedHeaders = options?.headers
|
|
150
|
-
? headersToRecord(normalizeHeaders(options.headers))
|
|
151
|
-
: {};
|
|
152
|
-
const requestHeaders = mergeHeaders(serialized?.headers ?? {}, providedHeaders);
|
|
153
|
-
const hasHeaders = Object.keys(requestHeaders).length > 0;
|
|
154
|
-
const response = yield* Effect.tryPromise({
|
|
155
|
-
try: () => fetchImpl(requestUrl, {
|
|
156
|
-
method: method.toUpperCase(),
|
|
157
|
-
...(hasHeaders ? { headers: requestHeaders } : {}),
|
|
158
|
-
...(serialized
|
|
159
|
-
? {
|
|
160
|
-
body: serialized.body,
|
|
161
|
-
}
|
|
162
|
-
: {}),
|
|
163
|
-
}),
|
|
164
|
-
catch: (cause) => new NetworkRequestError({
|
|
165
|
-
method,
|
|
166
|
-
url: requestUrl,
|
|
167
|
-
message: formatMessage(cause, "Network request failed"),
|
|
168
|
-
}),
|
|
169
|
-
});
|
|
170
|
-
return toNetworkResponse(response, context);
|
|
171
|
-
});
|
|
172
|
-
//# sourceMappingURL=network.js.map
|
package/dist/network.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"network.js","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"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","sourcesContent":["import { Context, Data, Effect, Layer } from \"effect\"\n\n/**\n * Supported HTTP methods accepted by {@link fetchNetwork}.\n */\nexport type NetworkMethod = \"get\" | \"post\" | \"delete\" | \"patch\"\n\n/**\n * Lightweight response model used by this package.\n *\n * Invariants:\n * - `json` is lazy: parsing only happens when the effect is run.\n * - `json` is memoized per response wrapper, so repeated evaluation does not\n * parse the same payload multiple times.\n */\nexport interface NetworkResponse {\n readonly status: number\n readonly statusText: string\n readonly statusMessage: string\n readonly headers: Readonly<Record<string, string>>\n readonly json: Effect.Effect<unknown, NetworkResponseError>\n}\n\n/**\n * Accepted request header input formats.\n */\nexport type NetworkHeaders =\n | Headers\n | Readonly<Record<string, string>>\n | Array<[string, string]>\n\n/**\n * Optional request options for {@link fetchNetwork}.\n */\nexport interface FetchNetworkOptions {\n readonly headers?: NetworkHeaders\n}\n\n/**\n * Effect service tag for the fetch implementation.\n *\n * Supply this service with `Effect.provide` / layers to swap fetch behavior\n * in tests or alternate runtimes.\n */\nexport class NetworkFetch extends Context.Tag(\"@passlock/node/network/Fetch\")<\n NetworkFetch,\n typeof fetch\n>() {}\n\n/**\n * Default live fetch layer backed by `globalThis.fetch`.\n */\nexport const NetworkFetchLive: Layer.Layer<NetworkFetch> = Layer.succeed(\n NetworkFetch,\n globalThis.fetch\n)\n\n/**\n * HTTP status buckets used by {@link matchStatus}.\n */\nexport type NetworkResponseStatusCase = \"2xx\" | \"3xx\" | \"4xx\" | \"5xx\"\n\ntype MatchStatusHandler<\n Resp extends NetworkResponse = NetworkResponse,\n A = unknown,\n E = unknown,\n> = (response: Resp) => Effect.Effect<A, E, never>\n\ntype HandlerEffect<\n Cases extends MatchStatusCases<Resp>,\n Resp extends NetworkResponse,\n Case extends NetworkResponseStatusCase | \"orElse\",\n> = Case extends keyof Cases\n ? NonNullable<Cases[Case]> extends MatchStatusHandler<Resp>\n ? ReturnType<NonNullable<Cases[Case]>>\n : never\n : never\n\ntype MatchStatusEffectUnion<\n Cases extends MatchStatusCases<Resp>,\n Resp extends NetworkResponse,\n> =\n | HandlerEffect<Cases, Resp, \"2xx\">\n | HandlerEffect<Cases, Resp, \"3xx\">\n | HandlerEffect<Cases, Resp, \"4xx\">\n | HandlerEffect<Cases, Resp, \"5xx\">\n | HandlerEffect<Cases, Resp, \"orElse\">\n\ntype MatchStatusResolvedHandler<\n Cases extends MatchStatusCases<Resp>,\n Resp extends NetworkResponse,\n> = NonNullable<\n Cases[\"2xx\"] | Cases[\"3xx\"] | Cases[\"4xx\"] | Cases[\"5xx\"] | Cases[\"orElse\"]\n>\n\ntype EffectSuccess<T> =\n T extends Effect.Effect<infer A, unknown, unknown> ? A : never\n\ntype EffectError<T> =\n T extends Effect.Effect<unknown, infer E, unknown> ? E : never\n\ntype EffectContext<T> =\n T extends Effect.Effect<unknown, unknown, infer R> ? R : never\n\n/**\n * Handlers used by {@link matchStatus}.\n *\n * Invariants:\n * - `orElse` is always required.\n * - Specific status family handlers are optional and fall back to `orElse`\n * when missing.\n */\nexport interface MatchStatusCases<\n Resp extends NetworkResponse = NetworkResponse,\n> {\n readonly \"2xx\"?: MatchStatusHandler<Resp>\n readonly \"3xx\"?: MatchStatusHandler<Resp>\n readonly \"4xx\"?: MatchStatusHandler<Resp>\n readonly \"5xx\"?: MatchStatusHandler<Resp>\n readonly orElse: MatchStatusHandler<Resp>\n}\n\ntype RequestContext = {\n readonly method: NetworkMethod\n readonly url: string\n}\n\n/**\n * Raised when the underlying fetch call fails before a response is received.\n */\nexport class NetworkRequestError extends Data.TaggedError(\n \"@error/NetworkRequest\"\n)<{\n readonly method: NetworkMethod\n readonly url: string\n readonly message: string\n}> {}\n\n/**\n * Raised when request payload serialization fails.\n */\nexport class NetworkPayloadError extends Data.TaggedError(\n \"@error/NetworkPayload\"\n)<{\n readonly method: NetworkMethod\n readonly message: string\n}> {}\n\n/**\n * Raised when response body parsing fails.\n */\nexport class NetworkResponseError extends Data.TaggedError(\n \"@error/NetworkResponse\"\n)<{\n readonly method: NetworkMethod\n readonly url: string\n readonly message: string\n}> {}\n\nconst formatMessage = (cause: unknown, fallback: string): string =>\n cause instanceof Error ? cause.message : fallback\n\n/**\n * Convert an HTTP status code into its status family bucket.\n *\n * Returns `undefined` for codes outside the 2xx-5xx families.\n */\nexport const statusToCase = (\n status: number\n): NetworkResponseStatusCase | undefined => {\n if (status >= 200 && status <= 299) return \"2xx\"\n if (status >= 300 && status <= 399) return \"3xx\"\n if (status >= 400 && status <= 499) return \"4xx\"\n if (status >= 500 && status <= 599) return \"5xx\"\n\n return undefined\n}\n\nconst resolveStatusHandler = <\n Resp extends NetworkResponse,\n Cases extends MatchStatusCases<Resp>,\n>(\n response: Resp,\n cases: Cases\n): MatchStatusResolvedHandler<Cases, Resp> => {\n const statusCase = statusToCase(response.status)\n if (!statusCase)\n return cases.orElse as MatchStatusResolvedHandler<Cases, Resp>\n\n const handler = cases[statusCase]\n return (handler ?? cases.orElse) as MatchStatusResolvedHandler<Cases, Resp>\n}\n\n/**\n * Route a {@link NetworkResponse} to the first matching status-family handler.\n *\n * Invariants:\n * - `2xx`/`3xx`/`4xx`/`5xx` handlers are matched by status family.\n * - `orElse` is always used as a fallback when no specific family handler exists.\n * - The returned effect type is inferred as the union of all handler effects.\n */\nexport const matchStatus = <\n Resp extends NetworkResponse,\n Cases extends MatchStatusCases<Resp>,\n>(\n response: Resp,\n cases: Cases\n): Effect.Effect<\n EffectSuccess<MatchStatusEffectUnion<Cases, Resp>>,\n EffectError<MatchStatusEffectUnion<Cases, Resp>>,\n EffectContext<MatchStatusEffectUnion<Cases, Resp>>\n> =>\n Effect.suspend(() => {\n const handler = resolveStatusHandler(response, cases)\n return handler(response)\n }) as Effect.Effect<\n EffectSuccess<MatchStatusEffectUnion<Cases, Resp>>,\n EffectError<MatchStatusEffectUnion<Cases, Resp>>,\n EffectContext<MatchStatusEffectUnion<Cases, Resp>>\n >\n\n/**\n * Serialize an optional payload into a JSON request body.\n *\n * Invariants:\n * - `GET` requests cannot carry a payload and fail with `NetworkPayloadError`.\n * - when a payload exists, `content-type: application/json` is emitted.\n */\nconst serializePayload = (\n method: NetworkMethod,\n payload?: unknown\n): Effect.Effect<\n | {\n readonly body: string\n readonly headers: Readonly<Record<string, string>>\n }\n | undefined,\n NetworkPayloadError\n> => {\n if (payload === undefined) {\n return Effect.succeed(undefined)\n }\n\n if (method === \"get\") {\n return Effect.fail(\n new NetworkPayloadError({\n method,\n message: \"GET requests do not support a request body\",\n })\n )\n }\n\n return Effect.try({\n try: () => ({\n body: JSON.stringify(payload),\n headers: { \"content-type\": \"application/json\" },\n }),\n catch: (cause) =>\n new NetworkPayloadError({\n method,\n message: formatMessage(cause, \"Unable to serialize payload to JSON\"),\n }),\n })\n}\n\n/**\n * Convert `Headers` into a readonly plain record.\n */\nexport const headersToRecord = (\n headers: Headers\n): Readonly<Record<string, string>> => Object.fromEntries(headers.entries())\n\nconst normalizeHeaders = (headers: NetworkHeaders): Headers => {\n if (headers instanceof Headers) {\n return new Headers(headers)\n }\n\n if (Array.isArray(headers)) {\n return new Headers(headers)\n }\n\n return new Headers(headers)\n}\n\nconst mergeHeaders = (\n ...headers: ReadonlyArray<Readonly<Record<string, string>>>\n): Readonly<Record<string, string>> => Object.assign({}, ...headers)\n\n/**\n * Build a lazy, memoized JSON parser effect from a response.\n *\n * Invariants:\n * - parsing happens on effect execution, not during response construction.\n * - parsing uses `response.clone()` so the original response body remains untouched.\n */\nconst makeJsonEffect = (\n response: Response,\n context: RequestContext\n): Effect.Effect<unknown, NetworkResponseError> => {\n let cached: Promise<unknown> | undefined\n\n return Effect.tryPromise({\n try: () => {\n cached = cached ?? response.clone().json()\n return cached\n },\n catch: (cause) =>\n new NetworkResponseError({\n method: context.method,\n url: context.url,\n message: formatMessage(cause, \"Unable to parse response JSON\"),\n }),\n })\n}\n\nconst toNetworkResponse = (\n response: Response,\n context: RequestContext\n): NetworkResponse => ({\n status: response.status,\n statusText: response.statusText,\n statusMessage: response.statusText,\n headers: headersToRecord(response.headers),\n json: makeJsonEffect(response, context),\n})\n\n/**\n * Execute a fetch request using the injected {@link NetworkFetch} service.\n *\n * Invariants:\n * - method is always normalized to upper-case before dispatch.\n * - JSON payload (if present) is serialized before request execution.\n * - caller headers override payload-derived headers when keys overlap.\n * - the returned `NetworkResponse.json` remains lazy.\n */\nexport const fetchNetwork = (\n url: string | URL,\n method: NetworkMethod,\n payload?: unknown,\n options?: FetchNetworkOptions\n): Effect.Effect<\n NetworkResponse,\n NetworkRequestError | NetworkPayloadError,\n NetworkFetch\n> =>\n Effect.gen(function* () {\n const requestUrl = String(url)\n const context: RequestContext = { method, url: requestUrl }\n const fetchImpl = yield* NetworkFetch\n const serialized = yield* serializePayload(method, payload)\n\n const providedHeaders = options?.headers\n ? headersToRecord(normalizeHeaders(options.headers))\n : {}\n\n const requestHeaders = mergeHeaders(\n serialized?.headers ?? {},\n providedHeaders\n )\n const hasHeaders = Object.keys(requestHeaders).length > 0\n\n const response = yield* Effect.tryPromise({\n try: () =>\n fetchImpl(requestUrl, {\n method: method.toUpperCase(),\n ...(hasHeaders ? { headers: requestHeaders } : {}),\n ...(serialized\n ? {\n body: serialized.body,\n }\n : {}),\n }),\n catch: (cause) =>\n new NetworkRequestError({\n method,\n url: requestUrl,\n message: formatMessage(cause, \"Network request failed\"),\n }),\n })\n\n return toNetworkResponse(response, context)\n })\n"]}
|