@passlock/node 0.9.30 → 2.0.0-beta.1

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.
Files changed (47) hide show
  1. package/README.md +12 -21
  2. package/README.template.md +11 -20
  3. package/dist/index.d.ts +4 -88
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +2 -80
  6. package/dist/index.js.map +1 -1
  7. package/dist/principal/effect.d.ts +53 -0
  8. package/dist/principal/effect.d.ts.map +1 -0
  9. package/dist/principal/effect.js +78 -0
  10. package/dist/principal/effect.js.map +1 -0
  11. package/dist/principal/index.d.ts +42 -0
  12. package/dist/principal/index.d.ts.map +1 -0
  13. package/dist/principal/index.js +60 -0
  14. package/dist/principal/index.js.map +1 -0
  15. package/dist/shared.d.ts +39 -0
  16. package/dist/shared.d.ts.map +1 -0
  17. package/dist/shared.js +21 -0
  18. package/dist/shared.js.map +1 -0
  19. package/dist/user/effect.d.ts +18 -0
  20. package/dist/user/effect.d.ts.map +1 -0
  21. package/dist/user/effect.js +27 -0
  22. package/dist/user/effect.js.map +1 -0
  23. package/dist/user/index.d.ts +18 -0
  24. package/dist/user/index.d.ts.map +1 -0
  25. package/dist/user/index.js +36 -0
  26. package/dist/user/index.js.map +1 -0
  27. package/package.json +59 -52
  28. package/LICENSE +0 -21
  29. package/dist/config/config.d.ts +0 -9
  30. package/dist/config/config.js +0 -4
  31. package/dist/config/config.js.map +0 -1
  32. package/dist/principal/principal.d.ts +0 -27
  33. package/dist/principal/principal.fixture.d.ts +0 -15
  34. package/dist/principal/principal.fixture.js +0 -67
  35. package/dist/principal/principal.fixture.js.map +0 -1
  36. package/dist/principal/principal.js +0 -88
  37. package/dist/principal/principal.js.map +0 -1
  38. package/dist/tsconfig.tsbuildinfo +0 -1
  39. package/dist/version.d.ts +0 -1
  40. package/dist/version.js +0 -2
  41. package/dist/version.js.map +0 -1
  42. package/src/config/config.ts +0 -10
  43. package/src/index.ts +0 -159
  44. package/src/principal/principal.fixture.ts +0 -107
  45. package/src/principal/principal.test.ts +0 -113
  46. package/src/principal/principal.ts +0 -160
  47. package/src/version.ts +0 -1
package/README.md CHANGED
@@ -8,20 +8,23 @@ in README.template.md and outputs to README.md
8
8
  </a>
9
9
  </div>
10
10
 
11
- <div>
12
- <h1 align="center">Passkeys, Social Login & more <br /> for Node.js apps</h1>
11
+ <div align="center">
12
+ <picture align="center">
13
+ <source srcset="https://passlock-assets.b-cdn.net/images/client-repo-banner.dark.svg" media="(prefers-color-scheme: dark)" />
14
+ <img align="center" width=550 height=50 src="https://passlock-assets.b-cdn.net/images/client-repo-banner.svg" />
15
+ </picture>
13
16
  <p align="center">
14
- Node SDK for Passkey authentication, Social Login using Apple, Google and more...
17
+ Backend NodeJS library to accompany the <a href="https://www.npmjs.com/package/@passlock/client">@passlock/client</a> package
15
18
  <br />
16
19
  <a href="https://passlock.dev"><strong>Project website »</strong></a>
17
20
  <br />
18
21
  <a href="https://github.com/passlock-dev/passlock">GitHub</a>
19
- ·
20
- <a href="">Demo</a>
21
22
  ·
22
- <a href="https://docs.passlock.dev">Documentation</a>
23
+ <a href="https://passlock.dev">Documentation</a>
24
+ ·
25
+ <a href="https://passlock.dev/getting-started/">Quick start</a>
23
26
  ·
24
- <a href="https://docs.passlock.dev/docs/tutorial/introduction">Tutorial</a>
27
+ <a href="https://passlock.dev/#demo">Demo</a>
25
28
  </p>
26
29
  </div>
27
30
 
@@ -33,23 +36,11 @@ For frontend usage please see the accompanying [@passlock/client][client] packag
33
36
 
34
37
  ## Requirements
35
38
 
36
- Node 16+
39
+ Node 22+
37
40
 
38
41
  ## Usage
39
42
 
40
- Generate a secure token in your frontend then use this API to obtain the passkey registration or authentication details:
41
-
42
- ```typescript
43
- import { Passlock } from '@passlock/node'
44
-
45
- const passlock = new Passlock({ tenancyId, apiKey })
46
-
47
- // token comes from your frontend
48
- const principal = await passlock.fetchPrincipal({ token })
49
-
50
- // get the user id
51
- console.log(principal.user.id)
52
- ```
43
+ Please see the [Quick start guide](https://passlock.dev/getting-started/)
53
44
 
54
45
  [contact]: https://passlock.dev/contact
55
46
  [client]: https://www.npmjs.com/package/@passlock/client
@@ -8,20 +8,23 @@ in README.template.md and outputs to README.md
8
8
  </a>
9
9
  </div>
10
10
 
11
- <div>
12
- <h1 align="center">Passkeys, Social Login & more <br /> for Node.js apps</h1>
11
+ <div align="center">
12
+ <picture align="center">
13
+ <source srcset="#{ASSETS}#/images/client-repo-banner.dark.svg" media="(prefers-color-scheme: dark)" />
14
+ <img align="center" width=550 height=50 src="#{ASSETS}#/images/client-repo-banner.svg" />
15
+ </picture>
13
16
  <p align="center">
14
- Node SDK for Passkey authentication, Social Login using Apple, Google and more...
17
+ Backend NodeJS library to accompany the <a href="https://www.npmjs.com/package/@passlock/client">@passlock/client</a> package
15
18
  <br />
16
19
  <a href="#{PASSLOCK_SITE}#"><strong>Project website »</strong></a>
17
20
  <br />
18
21
  <a href="#{GITHUB_REPO}#">GitHub</a>
19
- ·
20
- <a href="#{DEMO_SITE}#">Demo</a>
21
22
  ·
22
23
  <a href="#{DOCS}#">Documentation</a>
23
24
  ·
24
- <a href="#{TUTORIAL}#">Tutorial</a>
25
+ <a href="#{TUTORIAL}#">Quick start</a>
26
+ ·
27
+ <a href="#{DEMO}#">Demo</a>
25
28
  </p>
26
29
  </div>
27
30
 
@@ -33,23 +36,11 @@ For frontend usage please see the accompanying [@passlock/client][client] packag
33
36
 
34
37
  ## Requirements
35
38
 
36
- Node 16+
39
+ Node 22+
37
40
 
38
41
  ## Usage
39
42
 
40
- Generate a secure token in your frontend then use this API to obtain the passkey registration or authentication details:
41
-
42
- ```typescript
43
- import { Passlock } from '@passlock/node'
44
-
45
- const passlock = new Passlock({ tenancyId, apiKey })
46
-
47
- // token comes from your frontend
48
- const principal = await passlock.fetchPrincipal({ token })
49
-
50
- // get the user id
51
- console.log(principal.user.id)
52
- ```
43
+ Please see the [Quick start guide](#{TUTORIAL}#)
53
44
 
54
45
  [contact]: https://passlock.dev/contact
55
46
  [client]: https://www.npmjs.com/package/@passlock/client
package/dist/index.d.ts CHANGED
@@ -1,88 +1,4 @@
1
- import { ErrorCode } from '@passlock/shared/dist/error/error.js';
2
- import { type PrincipalRequest } from './principal/principal.js';
3
- export type { PrincipalRequest } from './principal/principal.js';
4
- export { ErrorCode } from '@passlock/shared/dist/error/error.js';
5
- export declare class PasslockError extends Error {
6
- readonly _tag = "PasslockError";
7
- readonly code: ErrorCode;
8
- constructor(message: string, code: ErrorCode);
9
- static readonly isError: (error: unknown) => error is PasslockError;
10
- }
11
- export declare class PasslockUnsafe {
12
- private readonly runtime;
13
- constructor(config: {
14
- tenancyId: string;
15
- apiKey: string;
16
- endpoint?: string;
17
- });
18
- private readonly runPromise;
19
- fetchPrincipal: (request: PrincipalRequest) => Promise<{
20
- readonly givenName?: string;
21
- readonly familyName?: string;
22
- readonly email?: string;
23
- readonly emailVerified?: boolean;
24
- readonly user?: {
25
- readonly id: string;
26
- readonly email: string;
27
- readonly givenName: string;
28
- readonly familyName: string;
29
- readonly emailVerified: boolean;
30
- };
31
- readonly iss: string;
32
- readonly aud: string;
33
- readonly sub: string;
34
- readonly iat: Date;
35
- readonly nbf: Date;
36
- readonly exp: Date;
37
- readonly jti: string;
38
- readonly token: string;
39
- readonly userVerified: boolean;
40
- readonly authType: "email" | "apple" | "google" | "passkey";
41
- readonly authId: string;
42
- readonly authStatement: {
43
- readonly userVerified: boolean;
44
- readonly authType: "email" | "apple" | "google" | "passkey";
45
- readonly authTimestamp: Date;
46
- };
47
- readonly expireAt: Date;
48
- }>;
49
- }
50
- export declare class Passlock {
51
- private readonly runtime;
52
- constructor(config: {
53
- tenancyId: string;
54
- apiKey: string;
55
- endpoint?: string;
56
- });
57
- private readonly runPromise;
58
- fetchPrincipal: (request: PrincipalRequest) => Promise<{
59
- readonly givenName?: string;
60
- readonly familyName?: string;
61
- readonly email?: string;
62
- readonly emailVerified?: boolean;
63
- readonly user?: {
64
- readonly id: string;
65
- readonly email: string;
66
- readonly givenName: string;
67
- readonly familyName: string;
68
- readonly emailVerified: boolean;
69
- };
70
- readonly iss: string;
71
- readonly aud: string;
72
- readonly sub: string;
73
- readonly iat: Date;
74
- readonly nbf: Date;
75
- readonly exp: Date;
76
- readonly jti: string;
77
- readonly token: string;
78
- readonly userVerified: boolean;
79
- readonly authType: "email" | "apple" | "google" | "passkey";
80
- readonly authId: string;
81
- readonly authStatement: {
82
- readonly userVerified: boolean;
83
- readonly authType: "email" | "apple" | "google" | "passkey";
84
- readonly authTimestamp: Date;
85
- };
86
- readonly expireAt: Date;
87
- } | PasslockError>;
88
- }
1
+ export type { ApiOptions, AuthorizedApiOptions } from "./shared.js";
2
+ export { type Principal, isPrincipal, exchangeCode, exchangeCodeUnsafe, verifyIdToken, verifyIdTokenUnsafe, } from "./principal/index.js";
3
+ export { type AssignUserRequest, type AssignedUser, assignUserUnsafe, } from "./user/index.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEpE,OAAO,EACL,KAAK,SAAS,EACd,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -1,81 +1,3 @@
1
- import { Effect as E, Layer as L, Runtime, Scope, pipe } from 'effect';
2
- import { ErrorCode } from '@passlock/shared/dist/error/error.js';
3
- import { Config } from './config/config.js';
4
- import { PrincipalService, PrincipalServiceLive, StreamResponseLive, } from './principal/principal.js';
5
- export { ErrorCode } from '@passlock/shared/dist/error/error.js';
6
- export class PasslockError extends Error {
7
- _tag = 'PasslockError';
8
- code;
9
- constructor(message, code) {
10
- super(message);
11
- this.code = code;
12
- }
13
- static isError = (error) => {
14
- return (typeof error === 'object' &&
15
- error !== null &&
16
- '_tag' in error &&
17
- error['_tag'] === 'PasslockError');
18
- };
19
- }
20
- const hasMessage = (defect) => {
21
- return (typeof defect === 'object' &&
22
- defect !== null &&
23
- 'message' in defect &&
24
- typeof defect['message'] === 'string');
25
- };
26
- const transformErrors = (effect) => {
27
- const withErrorHandling = E.catchTags(effect, {
28
- NotFound: e => E.succeed(new PasslockError(e.message, ErrorCode.NotFound)),
29
- Unauthorized: e => E.succeed(new PasslockError(e.message, ErrorCode.Unauthorized)),
30
- Forbidden: e => E.succeed(new PasslockError(e.message, ErrorCode.Forbidden)),
31
- InternalServerError: e => E.succeed(new PasslockError(e.message, ErrorCode.InternalServerError)),
32
- });
33
- const sandboxed = E.sandbox(withErrorHandling);
34
- const withSandboxing = E.catchTags(sandboxed, {
35
- Die: ({ defect }) => {
36
- return hasMessage(defect)
37
- ? E.succeed(new PasslockError(defect.message, ErrorCode.InternalServerError))
38
- : E.succeed(new PasslockError('Sorry, something went wrong', ErrorCode.InternalServerError));
39
- },
40
- Interrupt: () => {
41
- console.error('Interrupt');
42
- return E.succeed(new PasslockError('Operation aborted', ErrorCode.InternalBrowserError));
43
- },
44
- Sequential: errors => {
45
- console.error(errors);
46
- return E.succeed(new PasslockError('Sorry, something went wrong', ErrorCode.InternalServerError));
47
- },
48
- Parallel: errors => {
49
- console.error(errors);
50
- return E.succeed(new PasslockError('Sorry, something went wrong', ErrorCode.InternalServerError));
51
- },
52
- });
53
- return E.unsandbox(withSandboxing);
54
- };
55
- export class PasslockUnsafe {
56
- runtime;
57
- constructor(config) {
58
- const configLive = L.succeed(Config, Config.of(config));
59
- const allLayers = pipe(PrincipalServiceLive, L.provide(configLive), L.provide(StreamResponseLive));
60
- const scope = E.runSync(Scope.make());
61
- this.runtime = E.runSync(L.toRuntime(allLayers).pipe(Scope.extend(scope)));
62
- }
63
- runPromise = (effect) => {
64
- return pipe(transformErrors(effect), E.flatMap(result => (PasslockError.isError(result) ? E.fail(result) : E.succeed(result))), effect => Runtime.runPromise(this.runtime)(effect));
65
- };
66
- fetchPrincipal = (request) => pipe(PrincipalService, E.flatMap(service => service.fetchPrincipal(request)), effect => this.runPromise(effect));
67
- }
68
- export class Passlock {
69
- runtime;
70
- constructor(config) {
71
- const configLive = L.succeed(Config, Config.of(config));
72
- const allLayers = pipe(PrincipalServiceLive, L.provide(configLive), L.provide(StreamResponseLive));
73
- const scope = E.runSync(Scope.make());
74
- this.runtime = E.runSync(L.toRuntime(allLayers).pipe(Scope.extend(scope)));
75
- }
76
- runPromise = (effect) => {
77
- return pipe(transformErrors(effect), effect => Runtime.runPromise(this.runtime)(effect));
78
- };
79
- fetchPrincipal = (request) => pipe(PrincipalService, E.flatMap(service => service.fetchPrincipal(request)), effect => this.runPromise(effect));
80
- }
1
+ export { isPrincipal, exchangeCode, exchangeCodeUnsafe, verifyIdToken, verifyIdTokenUnsafe, } from "./principal/index.js";
2
+ export { assignUserUnsafe, } from "./user/index.js";
81
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAGL,gBAAgB,GACjB,MAAM,iBAAiB,CAAC","sourcesContent":["export type { ApiOptions, AuthorizedApiOptions } from \"./shared.js\";\n\nexport {\n type Principal,\n isPrincipal,\n exchangeCode,\n exchangeCodeUnsafe,\n verifyIdToken,\n verifyIdTokenUnsafe,\n} from \"./principal/index.js\";\n\nexport {\n type AssignUserRequest,\n type AssignedUser,\n assignUserUnsafe,\n} from \"./user/index.js\";\n"]}
@@ -0,0 +1,53 @@
1
+ import { HttpClient } from "@effect/platform";
2
+ import type { RequestError, ResponseError } from "@effect/platform/HttpClientError";
3
+ import { Effect, Schema } from "effect";
4
+ import type { ParseError } from "effect/ParseResult";
5
+ import { Forbidden, type ApiOptions, type AuthorizedApiOptions } from "../shared.js";
6
+ declare const InvalidCode_base: Schema.TaggedErrorClass<InvalidCode, "@error/InvalidCode", {
7
+ readonly _tag: Schema.tag<"@error/InvalidCode">;
8
+ } & {
9
+ message: typeof Schema.String;
10
+ }>;
11
+ export declare class InvalidCode extends InvalidCode_base {
12
+ static isInvalidCode: (payload: unknown) => payload is InvalidCode;
13
+ }
14
+ export declare const Principal: Schema.TaggedStruct<"Principal", {
15
+ tenancyId: typeof Schema.String;
16
+ userId: typeof Schema.String;
17
+ code: typeof Schema.String;
18
+ authenticatorId: typeof Schema.String;
19
+ passkey: Schema.optionalWith<Schema.Struct<{
20
+ userVerified: Schema.optionalWith<typeof Schema.Boolean, {
21
+ nullable: true;
22
+ }>;
23
+ }>, {
24
+ nullable: true;
25
+ }>;
26
+ createdAt: typeof Schema.DateFromNumber;
27
+ expiresAt: typeof Schema.DateFromNumber;
28
+ }>;
29
+ export type Principal = typeof Principal.Type;
30
+ export declare const isPrincipal: (payload: unknown) => payload is Principal;
31
+ export declare const IdToken: Schema.TaggedStruct<"IdToken", {
32
+ "a:id": typeof Schema.String;
33
+ "a:typ": typeof Schema.String;
34
+ iss: Schema.Literal<["passlock.dev"]>;
35
+ "pk:uv": typeof Schema.Boolean;
36
+ sub: typeof Schema.String;
37
+ jti: typeof Schema.String;
38
+ aud: typeof Schema.String;
39
+ iat: typeof Schema.Number;
40
+ exp: typeof Schema.Number;
41
+ }>;
42
+ export type IdToken = typeof IdToken.Type;
43
+ export declare const exchangeCode: (code: string, options: AuthorizedApiOptions) => Effect.Effect<Principal, InvalidCode | Forbidden | ParseError | RequestError | ResponseError, HttpClient.HttpClient>;
44
+ declare const VerificationError_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 & {
45
+ readonly _tag: "VerificationError";
46
+ } & Readonly<A>;
47
+ export declare class VerificationError extends VerificationError_base<{
48
+ message: string;
49
+ }> {
50
+ }
51
+ export declare const verifyIdToken: (token: string, options: ApiOptions) => Effect.Effect<Principal, VerificationError | ParseError>;
52
+ export {};
53
+ //# sourceMappingURL=effect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../src/principal/effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,kBAAkB,CAAC;AAClE,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACd,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAQ,MAAM,EAAe,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,OAAO,EACL,SAAS,EACT,KAAK,UAAU,EACf,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAC;;;;;;AAEtB,qBAAa,WAAY,SAAQ,gBAEkB;IACjD,MAAM,CAAC,aAAa,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,WAAW,CAC/B;CACnC;AAED,eAAO,MAAM,SAAS;;;;;;;;;;;;;;EAepB,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAC;AAE9C,eAAO,MAAM,WAAW,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,SAC3B,CAAC;AAEhC,eAAO,MAAM,OAAO;;;;;;;;;;EAUlB,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAC;AAE1C,eAAO,MAAM,YAAY,GACvB,MAAM,MAAM,EACZ,SAAS,oBAAoB,KAC5B,MAAM,CAAC,MAAM,CACd,SAAS,EACT,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,aAAa,EACnE,UAAU,CAAC,UAAU,CA4BnB,CAAC;;;;AAEL,qBAAa,iBAAkB,SAAQ,uBAAsC;IAC3E,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;CAAG;AAEL,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,EACb,SAAS,UAAU,KAClB,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,iBAAiB,GAAG,UAAU,CAsCtD,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { HttpClient, HttpClientResponse } from "@effect/platform";
2
+ import { Data, Effect, Match, pipe, Schema } from "effect";
3
+ import * as jose from "jose";
4
+ import { Forbidden, } from "../shared.js";
5
+ export class InvalidCode extends Schema.TaggedError("@error/InvalidCode")("@error/InvalidCode", { message: Schema.String }) {
6
+ static isInvalidCode = (payload) => Schema.is(InvalidCode)(payload);
7
+ }
8
+ export const Principal = Schema.TaggedStruct("Principal", {
9
+ tenancyId: Schema.String,
10
+ userId: Schema.String,
11
+ code: Schema.String,
12
+ authenticatorId: Schema.String,
13
+ passkey: Schema.optionalWith(Schema.Struct({
14
+ userVerified: Schema.optionalWith(Schema.Boolean, { nullable: true }),
15
+ }), {
16
+ nullable: true,
17
+ }),
18
+ createdAt: Schema.DateFromNumber,
19
+ expiresAt: Schema.DateFromNumber,
20
+ });
21
+ export const isPrincipal = (payload) => Schema.is(Principal)(payload);
22
+ export const IdToken = Schema.TaggedStruct("IdToken", {
23
+ "a:id": Schema.String,
24
+ "a:typ": Schema.String,
25
+ iss: Schema.Literal("passlock.dev"),
26
+ "pk:uv": Schema.Boolean,
27
+ sub: Schema.String,
28
+ jti: Schema.String,
29
+ aud: Schema.String,
30
+ iat: Schema.Number,
31
+ exp: Schema.Number,
32
+ });
33
+ export const exchangeCode = (code, options) => Effect.gen(function* () {
34
+ const client = yield* HttpClient.HttpClient;
35
+ const baseUrl = options.endpoint ?? "https://api.passlock.dev";
36
+ const url = new URL(`/${options.tenancyId}/principal/${code}`, baseUrl);
37
+ const response = yield* pipe(client.get(url, {
38
+ headers: { Authorization: `Bearer ${options.apiKey}` },
39
+ }));
40
+ const encoded = yield* HttpClientResponse.matchStatus(response, {
41
+ "2xx": () => HttpClientResponse.schemaBodyJson(Principal)(response),
42
+ orElse: () => HttpClientResponse.schemaBodyJson(Schema.Union(InvalidCode, Forbidden))(response),
43
+ });
44
+ return yield* pipe(Match.value(encoded), Match.tag("Principal", (principal) => Effect.succeed(principal)), Match.tag("@error/InvalidCode", (err) => Effect.fail(err)), Match.tag("@error/Forbidden", (err) => Effect.fail(err)), Match.exhaustive);
45
+ });
46
+ export class VerificationError extends Data.TaggedError("VerificationError") {
47
+ }
48
+ export const verifyIdToken = (token, options) => Effect.gen(function* () {
49
+ const baseUrl = options.endpoint ?? "https://api.passlock.dev";
50
+ const JWKS = jose.createRemoteJWKSet(new URL("/.well-known/jwks.json", baseUrl));
51
+ const { payload } = yield* Effect.tryPromise({
52
+ try: () => jose.jwtVerify(token, JWKS, {
53
+ issuer: "passlock.dev",
54
+ audience: options.tenancyId,
55
+ }),
56
+ catch: (err) => err instanceof Error
57
+ ? new VerificationError({ message: err.message })
58
+ : new VerificationError({ message: String(err) }),
59
+ });
60
+ const idToken = yield* Schema.decodeUnknown(IdToken)({
61
+ ...payload,
62
+ _tag: "IdToken",
63
+ });
64
+ const principal = {
65
+ _tag: "Principal",
66
+ tenancyId: options.tenancyId,
67
+ userId: idToken.sub,
68
+ code: idToken.jti,
69
+ authenticatorId: idToken["a:id"],
70
+ passkey: {
71
+ userVerified: idToken["pk:uv"],
72
+ },
73
+ createdAt: new Date(idToken.iat * 1000),
74
+ expiresAt: new Date(idToken.exp * 1000),
75
+ };
76
+ return principal;
77
+ });
78
+ //# sourceMappingURL=effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect.js","sourceRoot":"","sources":["../../src/principal/effect.ts"],"names":[],"mappings":"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","sourcesContent":["import { HttpClient, HttpClientResponse } from \"@effect/platform\";\nimport type {\n RequestError,\n ResponseError,\n} from \"@effect/platform/HttpClientError\";\nimport { Data, Effect, Match, pipe, Schema } from \"effect\";\nimport type { ParseError } from \"effect/ParseResult\";\nimport * as jose from \"jose\";\n\nimport {\n Forbidden,\n type ApiOptions,\n type AuthorizedApiOptions,\n} from \"../shared.js\";\n\nexport class InvalidCode extends Schema.TaggedError<InvalidCode>(\n \"@error/InvalidCode\",\n)(\"@error/InvalidCode\", { message: Schema.String }) {\n static isInvalidCode = (payload: unknown): payload is InvalidCode =>\n Schema.is(InvalidCode)(payload);\n}\n\nexport const Principal = Schema.TaggedStruct(\"Principal\", {\n tenancyId: Schema.String,\n userId: Schema.String,\n code: Schema.String,\n authenticatorId: Schema.String,\n passkey: Schema.optionalWith(\n Schema.Struct({\n userVerified: Schema.optionalWith(Schema.Boolean, { nullable: true }),\n }),\n {\n nullable: true,\n },\n ),\n createdAt: Schema.DateFromNumber,\n expiresAt: Schema.DateFromNumber,\n});\n\nexport type Principal = typeof Principal.Type;\n\nexport const isPrincipal = (payload: unknown): payload is Principal =>\n Schema.is(Principal)(payload);\n\nexport const IdToken = Schema.TaggedStruct(\"IdToken\", {\n \"a:id\": Schema.String,\n \"a:typ\": Schema.String,\n iss: Schema.Literal(\"passlock.dev\"),\n \"pk:uv\": Schema.Boolean,\n sub: Schema.String,\n jti: Schema.String,\n aud: Schema.String,\n iat: Schema.Number,\n exp: Schema.Number,\n});\n\nexport type IdToken = typeof IdToken.Type;\n\nexport const exchangeCode = (\n code: string,\n options: AuthorizedApiOptions,\n): Effect.Effect<\n Principal,\n InvalidCode | Forbidden | ParseError | RequestError | ResponseError,\n HttpClient.HttpClient\n> =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient;\n const baseUrl = options.endpoint ?? \"https://api.passlock.dev\";\n const url = new URL(`/${options.tenancyId}/principal/${code}`, baseUrl);\n\n const response = yield* pipe(\n client.get(url, {\n headers: { Authorization: `Bearer ${options.apiKey}` },\n }),\n );\n\n const encoded = yield* HttpClientResponse.matchStatus(response, {\n \"2xx\": () => HttpClientResponse.schemaBodyJson(Principal)(response),\n orElse: () =>\n HttpClientResponse.schemaBodyJson(Schema.Union(InvalidCode, Forbidden))(\n response,\n ),\n });\n\n return yield* pipe(\n Match.value(encoded),\n Match.tag(\"Principal\", (principal) => Effect.succeed(principal)),\n Match.tag(\"@error/InvalidCode\", (err) => Effect.fail(err)),\n Match.tag(\"@error/Forbidden\", (err) => Effect.fail(err)),\n Match.exhaustive,\n );\n });\n\nexport class VerificationError extends Data.TaggedError(\"VerificationError\")<{\n message: string;\n}> {}\n\nexport const verifyIdToken = (\n token: string,\n options: ApiOptions,\n): Effect.Effect<Principal, VerificationError | ParseError> =>\n Effect.gen(function* () {\n const baseUrl = options.endpoint ?? \"https://api.passlock.dev\";\n const JWKS = jose.createRemoteJWKSet(\n new URL(\"/.well-known/jwks.json\", baseUrl),\n );\n\n const { payload } = yield* Effect.tryPromise({\n try: () =>\n jose.jwtVerify(token, JWKS, {\n issuer: \"passlock.dev\",\n audience: options.tenancyId,\n }),\n catch: (err) =>\n err instanceof Error\n ? new VerificationError({ message: err.message })\n : new VerificationError({ message: String(err) }),\n });\n\n const idToken = yield* Schema.decodeUnknown(IdToken)({\n ...payload,\n _tag: \"IdToken\",\n });\n\n const principal: Principal = {\n _tag: \"Principal\",\n tenancyId: options.tenancyId,\n userId: idToken.sub,\n code: idToken.jti,\n authenticatorId: idToken[\"a:id\"],\n passkey: {\n userVerified: idToken[\"pk:uv\"],\n },\n createdAt: new Date(idToken.iat * 1000),\n expiresAt: new Date(idToken.exp * 1000),\n };\n\n return principal;\n });\n"]}
@@ -0,0 +1,42 @@
1
+ import { type Principal } from "./effect.js";
2
+ import type { VerificationError, InvalidCode } from "./effect.js";
3
+ import { type Forbidden, type ApiOptions, type AuthorizedApiOptions } from "../shared.js";
4
+ export type { VerificationError, Principal } from "./effect.js";
5
+ export { isPrincipal } from "./effect.js";
6
+ /**
7
+ * Call the Passlock backend API to exchange a code for a Principal
8
+ * @param code
9
+ * @package options
10
+ * @returns
11
+ */
12
+ export declare const exchangeCode: (code: string, options: AuthorizedApiOptions) => Promise<Principal | Forbidden | InvalidCode>;
13
+ /**
14
+ * Call the Passlock backend API to exchange a code for a Principal
15
+ * @param code
16
+ * @package options
17
+ * @returns
18
+ */
19
+ export declare const exchangeCodeUnsafe: (code: string, options: AuthorizedApiOptions) => Promise<Principal>;
20
+ /**
21
+ * Decode and verify a Passlock idToken.
22
+ * Note: This will make a network call to the passlock.dev/.well-known/jwks.json
23
+ * endpoint to fetch the relevant public key. The response will be cached, however
24
+ * bear in mind that for something like AWS lambda it will make the call on every
25
+ * cold start so might actually be slower than {@link exchangeCode}
26
+ * @param token
27
+ * @param options
28
+ * @returns
29
+ */
30
+ export declare const verifyIdToken: (token: string, options: ApiOptions) => Promise<Principal | VerificationError>;
31
+ /**
32
+ * Decode and verify a Passlock idToken.
33
+ * Note: This will make a network call to the passlock.dev/.well-known/jwks.json
34
+ * endpoint to fetch the relevant public key. The response will be cached, however
35
+ * bear in mind that for something like AWS lambda it will make the call on every
36
+ * cold start so might actually be slower than {@link exchangeCode}
37
+ * @param token
38
+ * @param options
39
+ * @returns
40
+ */
41
+ export declare const verifyIdTokenUnsafe: (token: string, options: ApiOptions) => Promise<Principal>;
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/principal/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,UAAU,EACf,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAC;AAEtB,YAAY,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,MAAM,EACZ,SAAS,oBAAoB,KAC5B,OAAO,CAAC,SAAS,GAAG,SAAS,GAAG,WAAW,CAc3C,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,MAAM,MAAM,EACZ,SAAS,oBAAoB,KAC5B,OAAO,CAAC,SAAS,CA8BjB,CAAC;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,EACb,SAAS,UAAU,KAClB,OAAO,CAAC,SAAS,GAAG,iBAAiB,CAYrC,CAAC;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,MAAM,EACb,SAAS,UAAU,KAClB,OAAO,CAAC,SAAS,CAajB,CAAC"}
@@ -0,0 +1,60 @@
1
+ import { FetchHttpClient } from "@effect/platform";
2
+ import { Effect, Either, identity, Match, pipe } from "effect";
3
+ import { exchangeCode as exchangeCodeE, verifyIdToken as verifyIdTokenE, } from "./effect.js";
4
+ import { UnexpectedError, } from "../shared.js";
5
+ export { isPrincipal } from "./effect.js";
6
+ /**
7
+ * Call the Passlock backend API to exchange a code for a Principal
8
+ * @param code
9
+ * @package options
10
+ * @returns
11
+ */
12
+ export const exchangeCode = (code, options) => pipe(exchangeCodeE(code, options), Effect.catchTags({
13
+ ParseError: (err) => Effect.die(err),
14
+ RequestError: (err) => Effect.die(err),
15
+ ResponseError: (err) => Effect.die(err),
16
+ }), Effect.match({
17
+ onSuccess: identity,
18
+ onFailure: identity,
19
+ }), Effect.provide(FetchHttpClient.layer), Effect.runPromise);
20
+ /**
21
+ * Call the Passlock backend API to exchange a code for a Principal
22
+ * @param code
23
+ * @package options
24
+ * @returns
25
+ */
26
+ export const exchangeCodeUnsafe = (code, options) => pipe(exchangeCodeE(code, options), Effect.either, Effect.provide(FetchHttpClient.layer), Effect.runPromise, (p) => p.then((response) => Either.match(response, {
27
+ onLeft: (err) => pipe(Match.value(err), Match.tag("ParseError", (err) => new UnexpectedError(err)), Match.tag("RequestError", (err) => new UnexpectedError(err)), Match.tag("ResponseError", (err) => new UnexpectedError(err)), Match.tag("@error/InvalidCode", (err) => new UnexpectedError(err)), Match.tag("@error/Forbidden", ({ _tag }) => new UnexpectedError({ _tag, message: "Forbidden" })), Match.exhaustive, (serverError) => Promise.reject(serverError)),
28
+ onRight: (success) => Promise.resolve(success),
29
+ })));
30
+ /**
31
+ * Decode and verify a Passlock idToken.
32
+ * Note: This will make a network call to the passlock.dev/.well-known/jwks.json
33
+ * endpoint to fetch the relevant public key. The response will be cached, however
34
+ * bear in mind that for something like AWS lambda it will make the call on every
35
+ * cold start so might actually be slower than {@link exchangeCode}
36
+ * @param token
37
+ * @param options
38
+ * @returns
39
+ */
40
+ export const verifyIdToken = (token, options) => pipe(verifyIdTokenE(token, options), Effect.catchTags({
41
+ ParseError: (err) => Effect.die(err),
42
+ }), Effect.match({
43
+ onSuccess: identity,
44
+ onFailure: identity,
45
+ }), Effect.provide(FetchHttpClient.layer), Effect.runPromise);
46
+ /**
47
+ * Decode and verify a Passlock idToken.
48
+ * Note: This will make a network call to the passlock.dev/.well-known/jwks.json
49
+ * endpoint to fetch the relevant public key. The response will be cached, however
50
+ * bear in mind that for something like AWS lambda it will make the call on every
51
+ * cold start so might actually be slower than {@link exchangeCode}
52
+ * @param token
53
+ * @param options
54
+ * @returns
55
+ */
56
+ export const verifyIdTokenUnsafe = (token, options) => pipe(verifyIdTokenE(token, options), Effect.either, Effect.provide(FetchHttpClient.layer), Effect.runPromise, (p) => p.then((response) => Either.match(response, {
57
+ onLeft: (err) => Promise.reject(new UnexpectedError(err)),
58
+ onRight: (success) => Promise.resolve(success),
59
+ })));
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/principal/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { FetchHttpClient } from \"@effect/platform\";\nimport { Effect, Either, identity, Match, pipe } from \"effect\";\n\nimport {\n type Principal,\n exchangeCode as exchangeCodeE,\n verifyIdToken as verifyIdTokenE,\n} from \"./effect.js\";\n\nimport type { VerificationError, InvalidCode } from \"./effect.js\";\n\nimport {\n type Forbidden,\n UnexpectedError,\n type ApiOptions,\n type AuthorizedApiOptions,\n} from \"../shared.js\";\n\nexport type { VerificationError, Principal } from \"./effect.js\";\n\nexport { isPrincipal } from \"./effect.js\";\n\n/**\n * Call the Passlock backend API to exchange a code for a Principal\n * @param code\n * @package options\n * @returns\n */\nexport const exchangeCode = (\n code: string,\n options: AuthorizedApiOptions,\n): Promise<Principal | Forbidden | InvalidCode> =>\n pipe(\n exchangeCodeE(code, options),\n Effect.catchTags({\n ParseError: (err) => Effect.die(err),\n RequestError: (err) => Effect.die(err),\n ResponseError: (err) => Effect.die(err),\n }),\n Effect.match({\n onSuccess: identity,\n onFailure: identity,\n }),\n Effect.provide(FetchHttpClient.layer),\n Effect.runPromise,\n );\n\n/**\n * Call the Passlock backend API to exchange a code for a Principal\n * @param code\n * @package options\n * @returns\n */\nexport const exchangeCodeUnsafe = (\n code: string,\n options: AuthorizedApiOptions,\n): Promise<Principal> =>\n pipe(\n exchangeCodeE(code, options),\n Effect.either,\n Effect.provide(FetchHttpClient.layer),\n Effect.runPromise,\n (p) =>\n p.then((response) =>\n Either.match(response, {\n onLeft: (err) =>\n pipe(\n Match.value(err),\n Match.tag(\"ParseError\", (err) => new UnexpectedError(err)),\n Match.tag(\"RequestError\", (err) => new UnexpectedError(err)),\n Match.tag(\"ResponseError\", (err) => new UnexpectedError(err)),\n Match.tag(\n \"@error/InvalidCode\",\n (err) => new UnexpectedError(err),\n ),\n Match.tag(\n \"@error/Forbidden\",\n ({ _tag }) =>\n new UnexpectedError({ _tag, message: \"Forbidden\" }),\n ),\n Match.exhaustive,\n (serverError) => Promise.reject(serverError),\n ),\n onRight: (success) => Promise.resolve(success),\n }),\n ),\n );\n\n/**\n * Decode and verify a Passlock idToken.\n * Note: This will make a network call to the passlock.dev/.well-known/jwks.json\n * endpoint to fetch the relevant public key. The response will be cached, however\n * bear in mind that for something like AWS lambda it will make the call on every\n * cold start so might actually be slower than {@link exchangeCode}\n * @param token\n * @param options\n * @returns\n */\nexport const verifyIdToken = (\n token: string,\n options: ApiOptions,\n): Promise<Principal | VerificationError> =>\n pipe(\n verifyIdTokenE(token, options),\n Effect.catchTags({\n ParseError: (err) => Effect.die(err),\n }),\n Effect.match({\n onSuccess: identity,\n onFailure: identity,\n }),\n Effect.provide(FetchHttpClient.layer),\n Effect.runPromise,\n );\n\n/**\n * Decode and verify a Passlock idToken.\n * Note: This will make a network call to the passlock.dev/.well-known/jwks.json\n * endpoint to fetch the relevant public key. The response will be cached, however\n * bear in mind that for something like AWS lambda it will make the call on every\n * cold start so might actually be slower than {@link exchangeCode}\n * @param token\n * @param options\n * @returns\n */\nexport const verifyIdTokenUnsafe = (\n token: string,\n options: ApiOptions,\n): Promise<Principal> =>\n pipe(\n verifyIdTokenE(token, options),\n Effect.either,\n Effect.provide(FetchHttpClient.layer),\n Effect.runPromise,\n (p) =>\n p.then((response) =>\n Either.match(response, {\n onLeft: (err) => Promise.reject(new UnexpectedError(err)),\n onRight: (success) => Promise.resolve(success),\n }),\n ),\n );\n"]}
@@ -0,0 +1,39 @@
1
+ import { Schema } from "effect";
2
+ export interface ApiOptions {
3
+ tenancyId: string;
4
+ /**
5
+ * @default https://api.passlock.dev
6
+ */
7
+ endpoint?: string;
8
+ }
9
+ export interface AuthorizedApiOptions extends ApiOptions {
10
+ apiKey: string;
11
+ }
12
+ declare const NotFound_base: Schema.TaggedErrorClass<NotFound, "@error/NotFound", {
13
+ readonly _tag: Schema.tag<"@error/NotFound">;
14
+ } & {
15
+ message: typeof Schema.String;
16
+ }>;
17
+ export declare class NotFound extends NotFound_base {
18
+ static isNotFound: (payload: unknown) => payload is NotFound;
19
+ }
20
+ declare const Unauthorized_base: Schema.TaggedErrorClass<Unauthorized, "@error/Unauthorized", {
21
+ readonly _tag: Schema.tag<"@error/Unauthorized">;
22
+ }>;
23
+ export declare class Unauthorized extends Unauthorized_base {
24
+ }
25
+ declare const Forbidden_base: Schema.TaggedErrorClass<Forbidden, "@error/Forbidden", {
26
+ readonly _tag: Schema.tag<"@error/Forbidden">;
27
+ }>;
28
+ export declare class Forbidden extends Forbidden_base {
29
+ }
30
+ export declare class UnexpectedError extends Error {
31
+ readonly _tag: string;
32
+ constructor(data: {
33
+ _tag: string;
34
+ message: string;
35
+ });
36
+ readonly toString: () => string;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAqB,SAAQ,UAAU;IACtD,MAAM,EAAE,MAAM,CAAC;CAChB;;;;;;AAED,qBAAa,QAAS,SAAQ,aAK7B;IACC,MAAM,CAAC,UAAU,GAAI,SAAS,OAAO,KAAG,OAAO,IAAI,QAAQ,CAC5B;CAChC;;;;AAGD,qBAAa,YAAa,SAAQ,iBAGjC;CAAG;;;;AAGJ,qBAAa,SAAU,SAAQ,cAG9B;CAAG;AAEJ,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAKnD,SAAkB,QAAQ,QAAO,MAAM,CACE;CAC1C"}