@shware/security 9.2.1 → 9.2.2

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.
@@ -30,9 +30,14 @@ var RequestError = class RequestError extends Error {
30
30
  Object.setPrototypeOf(this, RequestError.prototype);
31
31
  }
32
32
  };
33
- function invalidArgument(reason, message, details) {
33
+ /**
34
+ * A malformed request: the `ErrorInfo` with `reason` first, then any further `details` (a
35
+ * `BadRequest` naming the fields a schema refused), so `getErrorInfo` finds the reason whatever
36
+ * else the body carries.
37
+ */
38
+ function invalidArgument(reason, message, details = []) {
34
39
  const body = errorBody(400, "INVALID_ARGUMENT", reason, message);
35
- if (details) body.error.details = details;
40
+ body.error.details.push(...details);
36
41
  return new RequestError(body);
37
42
  }
38
43
  function unauthenticated(message) {
@@ -1 +1 @@
1
- {"version":3,"file":"respond.cjs","names":["AuthenticationError","OAuth2Error"],"sources":["../../src/auth/respond.ts"],"sourcesContent":["import { OAuth2Error, type OAuth2ErrorType } from '../oauth2/error';\nimport { AuthenticationError } from './error';\n\n/**\n * How the JSON routes answer a failure: a google.rpc error body, as `@shware/http` reads it, with\n * one `ErrorInfo` whose `reason` the client branches on. The redirect flow answers differently\n * (`error=…` on `errorUri`, see `Auth.redirect`), since a page, not a client, reads it.\n */\nexport interface ErrorBody {\n error: {\n code: number;\n status: string;\n message: string;\n details: unknown[];\n };\n}\n\nconst ERROR_INFO = 'type.googleapis.com/google.rpc.ErrorInfo';\n\nexport function errorBody(\n code: number,\n status: string,\n reason: string,\n message: string,\n metadata?: Record<string, string>\n): ErrorBody {\n const info = { '@type': ERROR_INFO, reason, ...(metadata ? { metadata } : {}) };\n return { error: { code, status, message, details: [info] } };\n}\n\n/**\n * A request a route cannot act on, answered as it is: malformed, too soon, not signed in. Thrown\n * by the validation helpers so a route reads as one straight line; `errorResponse` turns it into\n * the response. Unlike `AuthenticationError`, which is about who is signing in, this is about\n * the request itself, so it is not the host's to throw.\n */\nexport class RequestError extends Error {\n readonly body: ErrorBody;\n\n constructor(body: ErrorBody) {\n super(body.error.message);\n this.name = 'RequestError';\n this.body = body;\n Object.setPrototypeOf(this, RequestError.prototype);\n }\n}\n\nexport function invalidArgument(reason: string, message: string, details?: unknown[]) {\n const body = errorBody(400, 'INVALID_ARGUMENT', reason, message);\n if (details) body.error.details = details;\n return new RequestError(body);\n}\n\nexport function unauthenticated(message: string) {\n return new RequestError(errorBody(401, 'UNAUTHENTICATED', 'UNAUTHENTICATED', message));\n}\n\nexport function resourceExhausted(reason: string, message: string) {\n return new RequestError(errorBody(429, 'RESOURCE_EXHAUSTED', reason, message));\n}\n\nexport function unavailable(reason: string, message: string) {\n return new RequestError(errorBody(503, 'UNAVAILABLE', reason, message));\n}\n\n/**\n * What an `OAuth2Error` from the provider client means to the caller of a JSON route: the request\n * named something that does not exist (400), the credential it sent was refused (403), or the\n * provider is down (503). Its message stays in the logs: it can name a client id or quote the\n * provider's response.\n */\nconst OAUTH2_STATUS: Record<OAuth2ErrorType, [code: number, status: string]> = {\n invalid_request: [400, 'INVALID_ARGUMENT'],\n invalid_scope: [400, 'INVALID_ARGUMENT'],\n unsupported_grant_type: [400, 'INVALID_ARGUMENT'],\n unsupported_response_type: [400, 'INVALID_ARGUMENT'],\n redirect_uri_mismatch: [400, 'INVALID_ARGUMENT'],\n invalid_client: [403, 'PERMISSION_DENIED'],\n invalid_grant: [403, 'PERMISSION_DENIED'],\n invalid_token: [403, 'PERMISSION_DENIED'],\n unauthorized_client: [403, 'PERMISSION_DENIED'],\n insufficient_scope: [403, 'PERMISSION_DENIED'],\n access_denied: [403, 'PERMISSION_DENIED'],\n server_error: [503, 'UNAVAILABLE'],\n temporarily_unavailable: [503, 'UNAVAILABLE'],\n};\n\n/**\n * The response a JSON route gives for an error it knows, or `null` for one it does not, which is\n * the host's (a 500). Every JSON route runs under this, so the three kinds of failure have one\n * mapping: a `RequestError` as it is, an `AuthenticationError` as `403 PERMISSION_DENIED` with the\n * reason and metadata (the host's refusal or the SDK's own: a wrong code, a replayed nonce), an\n * `OAuth2Error` by what it means (`OAUTH2_<error>` as the reason). Exported for the host's error\n * handler, so a flow of its own that calls `Auth` directly (`verifyEmailCode`) answers the same way:\n * `errorResponse(error) ?? yourHandler(error)`.\n */\nexport function errorResponse(error: unknown): Response | null {\n if (error instanceof RequestError) {\n return Response.json(error.body, { status: error.body.error.code });\n }\n if (error instanceof AuthenticationError) {\n const body = errorBody(403, 'PERMISSION_DENIED', error.reason, error.message, error.metadata);\n return Response.json(body, { status: body.error.code });\n }\n if (error instanceof OAuth2Error) {\n console.warn('OAuth2 login failed', error);\n const [code, status] = OAUTH2_STATUS[error.error] ?? [503, 'UNAVAILABLE'];\n const reason = `OAUTH2_${error.error.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`;\n const body = errorBody(code, status, reason, `OAuth2 ${error.error}`);\n return Response.json(body, { status: body.error.code });\n }\n return null;\n}\n"],"mappings":";;;;AAiBA,MAAM,aAAa;AAEnB,SAAgB,UACd,MACA,QACA,QACA,SACA,UACW;CAEX,OAAO,EAAE,OAAO;EAAE;EAAM;EAAQ;EAAS,SAAS,CAAC;GADpC,SAAS;GAAY;GAAQ,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EACrB,CAAC;CAAE,EAAE;AAC7D;;;;;;;AAQA,IAAa,eAAb,MAAa,qBAAqB,MAAM;CACtC;CAEA,YAAY,MAAiB;EAC3B,MAAM,KAAK,MAAM,OAAO;EACxB,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,aAAa,SAAS;CACpD;AACF;AAEA,SAAgB,gBAAgB,QAAgB,SAAiB,SAAqB;CACpF,MAAM,OAAO,UAAU,KAAK,oBAAoB,QAAQ,OAAO;CAC/D,IAAI,SAAS,KAAK,MAAM,UAAU;CAClC,OAAO,IAAI,aAAa,IAAI;AAC9B;AAEA,SAAgB,gBAAgB,SAAiB;CAC/C,OAAO,IAAI,aAAa,UAAU,KAAK,mBAAmB,mBAAmB,OAAO,CAAC;AACvF;AAEA,SAAgB,kBAAkB,QAAgB,SAAiB;CACjE,OAAO,IAAI,aAAa,UAAU,KAAK,sBAAsB,QAAQ,OAAO,CAAC;AAC/E;AAEA,SAAgB,YAAY,QAAgB,SAAiB;CAC3D,OAAO,IAAI,aAAa,UAAU,KAAK,eAAe,QAAQ,OAAO,CAAC;AACxE;;;;;;;AAQA,MAAM,gBAAyE;CAC7E,iBAAiB,CAAC,KAAK,kBAAkB;CACzC,eAAe,CAAC,KAAK,kBAAkB;CACvC,wBAAwB,CAAC,KAAK,kBAAkB;CAChD,2BAA2B,CAAC,KAAK,kBAAkB;CACnD,uBAAuB,CAAC,KAAK,kBAAkB;CAC/C,gBAAgB,CAAC,KAAK,mBAAmB;CACzC,eAAe,CAAC,KAAK,mBAAmB;CACxC,eAAe,CAAC,KAAK,mBAAmB;CACxC,qBAAqB,CAAC,KAAK,mBAAmB;CAC9C,oBAAoB,CAAC,KAAK,mBAAmB;CAC7C,eAAe,CAAC,KAAK,mBAAmB;CACxC,cAAc,CAAC,KAAK,aAAa;CACjC,yBAAyB,CAAC,KAAK,aAAa;AAC9C;;;;;;;;;;AAWA,SAAgB,cAAc,OAAiC;CAC7D,IAAI,iBAAiB,cACnB,OAAO,SAAS,KAAK,MAAM,MAAM,EAAE,QAAQ,MAAM,KAAK,MAAM,KAAK,CAAC;CAEpE,IAAI,iBAAiBA,mBAAAA,qBAAqB;EACxC,MAAM,OAAO,UAAU,KAAK,qBAAqB,MAAM,QAAQ,MAAM,SAAS,MAAM,QAAQ;EAC5F,OAAO,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,MAAM,KAAK,CAAC;CACxD;CACA,IAAI,iBAAiBC,qBAAAA,aAAa;EAChC,QAAQ,KAAK,uBAAuB,KAAK;EACzC,MAAM,CAAC,MAAM,UAAU,cAAc,MAAM,UAAU,CAAC,KAAK,aAAa;EAExE,MAAM,OAAO,UAAU,MAAM,QAAQ,UADZ,MAAM,MAAM,YAAY,CAAC,CAAC,QAAQ,cAAc,GAAG,KAC/B,UAAU,MAAM,OAAO;EACpE,OAAO,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,MAAM,KAAK,CAAC;CACxD;CACA,OAAO;AACT"}
1
+ {"version":3,"file":"respond.cjs","names":["AuthenticationError","OAuth2Error"],"sources":["../../src/auth/respond.ts"],"sourcesContent":["import { OAuth2Error, type OAuth2ErrorType } from '../oauth2/error';\nimport { AuthenticationError } from './error';\n\n/**\n * How the JSON routes answer a failure: a google.rpc error body, as `@shware/http` reads it, with\n * one `ErrorInfo` whose `reason` the client branches on. The redirect flow answers differently\n * (`error=…` on `errorUri`, see `Auth.redirect`), since a page, not a client, reads it.\n */\nexport interface ErrorBody {\n error: {\n code: number;\n status: string;\n message: string;\n details: unknown[];\n };\n}\n\nconst ERROR_INFO = 'type.googleapis.com/google.rpc.ErrorInfo';\n\nexport function errorBody(\n code: number,\n status: string,\n reason: string,\n message: string,\n metadata?: Record<string, string>\n): ErrorBody {\n const info = { '@type': ERROR_INFO, reason, ...(metadata ? { metadata } : {}) };\n return { error: { code, status, message, details: [info] } };\n}\n\n/**\n * A request a route cannot act on, answered as it is: malformed, too soon, not signed in. Thrown\n * by the validation helpers so a route reads as one straight line; `errorResponse` turns it into\n * the response. Unlike `AuthenticationError`, which is about who is signing in, this is about\n * the request itself, so it is not the host's to throw.\n */\nexport class RequestError extends Error {\n readonly body: ErrorBody;\n\n constructor(body: ErrorBody) {\n super(body.error.message);\n this.name = 'RequestError';\n this.body = body;\n Object.setPrototypeOf(this, RequestError.prototype);\n }\n}\n\n/**\n * A malformed request: the `ErrorInfo` with `reason` first, then any further `details` (a\n * `BadRequest` naming the fields a schema refused), so `getErrorInfo` finds the reason whatever\n * else the body carries.\n */\nexport function invalidArgument(reason: string, message: string, details: unknown[] = []) {\n const body = errorBody(400, 'INVALID_ARGUMENT', reason, message);\n body.error.details.push(...details);\n return new RequestError(body);\n}\n\nexport function unauthenticated(message: string) {\n return new RequestError(errorBody(401, 'UNAUTHENTICATED', 'UNAUTHENTICATED', message));\n}\n\nexport function resourceExhausted(reason: string, message: string) {\n return new RequestError(errorBody(429, 'RESOURCE_EXHAUSTED', reason, message));\n}\n\nexport function unavailable(reason: string, message: string) {\n return new RequestError(errorBody(503, 'UNAVAILABLE', reason, message));\n}\n\n/**\n * What an `OAuth2Error` from the provider client means to the caller of a JSON route: the request\n * named something that does not exist (400), the credential it sent was refused (403), or the\n * provider is down (503). Its message stays in the logs: it can name a client id or quote the\n * provider's response.\n */\nconst OAUTH2_STATUS: Record<OAuth2ErrorType, [code: number, status: string]> = {\n invalid_request: [400, 'INVALID_ARGUMENT'],\n invalid_scope: [400, 'INVALID_ARGUMENT'],\n unsupported_grant_type: [400, 'INVALID_ARGUMENT'],\n unsupported_response_type: [400, 'INVALID_ARGUMENT'],\n redirect_uri_mismatch: [400, 'INVALID_ARGUMENT'],\n invalid_client: [403, 'PERMISSION_DENIED'],\n invalid_grant: [403, 'PERMISSION_DENIED'],\n invalid_token: [403, 'PERMISSION_DENIED'],\n unauthorized_client: [403, 'PERMISSION_DENIED'],\n insufficient_scope: [403, 'PERMISSION_DENIED'],\n access_denied: [403, 'PERMISSION_DENIED'],\n server_error: [503, 'UNAVAILABLE'],\n temporarily_unavailable: [503, 'UNAVAILABLE'],\n};\n\n/**\n * The response a JSON route gives for an error it knows, or `null` for one it does not, which is\n * the host's (a 500). Every JSON route runs under this, so the three kinds of failure have one\n * mapping: a `RequestError` as it is, an `AuthenticationError` as `403 PERMISSION_DENIED` with the\n * reason and metadata (the host's refusal or the SDK's own: a wrong code, a replayed nonce), an\n * `OAuth2Error` by what it means (`OAUTH2_<error>` as the reason). Exported for the host's error\n * handler, so a flow of its own that calls `Auth` directly (`verifyEmailCode`) answers the same way:\n * `errorResponse(error) ?? yourHandler(error)`.\n */\nexport function errorResponse(error: unknown): Response | null {\n if (error instanceof RequestError) {\n return Response.json(error.body, { status: error.body.error.code });\n }\n if (error instanceof AuthenticationError) {\n const body = errorBody(403, 'PERMISSION_DENIED', error.reason, error.message, error.metadata);\n return Response.json(body, { status: body.error.code });\n }\n if (error instanceof OAuth2Error) {\n console.warn('OAuth2 login failed', error);\n const [code, status] = OAUTH2_STATUS[error.error] ?? [503, 'UNAVAILABLE'];\n const reason = `OAUTH2_${error.error.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`;\n const body = errorBody(code, status, reason, `OAuth2 ${error.error}`);\n return Response.json(body, { status: body.error.code });\n }\n return null;\n}\n"],"mappings":";;;;AAiBA,MAAM,aAAa;AAEnB,SAAgB,UACd,MACA,QACA,QACA,SACA,UACW;CAEX,OAAO,EAAE,OAAO;EAAE;EAAM;EAAQ;EAAS,SAAS,CAAC;GADpC,SAAS;GAAY;GAAQ,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EACrB,CAAC;CAAE,EAAE;AAC7D;;;;;;;AAQA,IAAa,eAAb,MAAa,qBAAqB,MAAM;CACtC;CAEA,YAAY,MAAiB;EAC3B,MAAM,KAAK,MAAM,OAAO;EACxB,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,aAAa,SAAS;CACpD;AACF;;;;;;AAOA,SAAgB,gBAAgB,QAAgB,SAAiB,UAAqB,CAAC,GAAG;CACxF,MAAM,OAAO,UAAU,KAAK,oBAAoB,QAAQ,OAAO;CAC/D,KAAK,MAAM,QAAQ,KAAK,GAAG,OAAO;CAClC,OAAO,IAAI,aAAa,IAAI;AAC9B;AAEA,SAAgB,gBAAgB,SAAiB;CAC/C,OAAO,IAAI,aAAa,UAAU,KAAK,mBAAmB,mBAAmB,OAAO,CAAC;AACvF;AAEA,SAAgB,kBAAkB,QAAgB,SAAiB;CACjE,OAAO,IAAI,aAAa,UAAU,KAAK,sBAAsB,QAAQ,OAAO,CAAC;AAC/E;AAEA,SAAgB,YAAY,QAAgB,SAAiB;CAC3D,OAAO,IAAI,aAAa,UAAU,KAAK,eAAe,QAAQ,OAAO,CAAC;AACxE;;;;;;;AAQA,MAAM,gBAAyE;CAC7E,iBAAiB,CAAC,KAAK,kBAAkB;CACzC,eAAe,CAAC,KAAK,kBAAkB;CACvC,wBAAwB,CAAC,KAAK,kBAAkB;CAChD,2BAA2B,CAAC,KAAK,kBAAkB;CACnD,uBAAuB,CAAC,KAAK,kBAAkB;CAC/C,gBAAgB,CAAC,KAAK,mBAAmB;CACzC,eAAe,CAAC,KAAK,mBAAmB;CACxC,eAAe,CAAC,KAAK,mBAAmB;CACxC,qBAAqB,CAAC,KAAK,mBAAmB;CAC9C,oBAAoB,CAAC,KAAK,mBAAmB;CAC7C,eAAe,CAAC,KAAK,mBAAmB;CACxC,cAAc,CAAC,KAAK,aAAa;CACjC,yBAAyB,CAAC,KAAK,aAAa;AAC9C;;;;;;;;;;AAWA,SAAgB,cAAc,OAAiC;CAC7D,IAAI,iBAAiB,cACnB,OAAO,SAAS,KAAK,MAAM,MAAM,EAAE,QAAQ,MAAM,KAAK,MAAM,KAAK,CAAC;CAEpE,IAAI,iBAAiBA,mBAAAA,qBAAqB;EACxC,MAAM,OAAO,UAAU,KAAK,qBAAqB,MAAM,QAAQ,MAAM,SAAS,MAAM,QAAQ;EAC5F,OAAO,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,MAAM,KAAK,CAAC;CACxD;CACA,IAAI,iBAAiBC,qBAAAA,aAAa;EAChC,QAAQ,KAAK,uBAAuB,KAAK;EACzC,MAAM,CAAC,MAAM,UAAU,cAAc,MAAM,UAAU,CAAC,KAAK,aAAa;EAExE,MAAM,OAAO,UAAU,MAAM,QAAQ,UADZ,MAAM,MAAM,YAAY,CAAC,CAAC,QAAQ,cAAc,GAAG,KAC/B,UAAU,MAAM,OAAO;EACpE,OAAO,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,MAAM,KAAK,CAAC;CACxD;CACA,OAAO;AACT"}
@@ -22,6 +22,11 @@ export declare class RequestError extends Error {
22
22
  readonly body: ErrorBody;
23
23
  constructor(body: ErrorBody);
24
24
  }
25
+ /**
26
+ * A malformed request: the `ErrorInfo` with `reason` first, then any further `details` (a
27
+ * `BadRequest` naming the fields a schema refused), so `getErrorInfo` finds the reason whatever
28
+ * else the body carries.
29
+ */
25
30
  export declare function invalidArgument(reason: string, message: string, details?: unknown[]): RequestError;
26
31
  export declare function unauthenticated(message: string): RequestError;
27
32
  export declare function resourceExhausted(reason: string, message: string): RequestError;
@@ -1 +1 @@
1
- {"version":3,"file":"respond.d.cts","names":[],"sources":["../../src/auth/respond.ts"],"mappings":";;;;;iBAQiB;EACf;IACE;IACA;IACA;IACA;;;wBAMY,UACd,cACA,gBACA,gBACA,iBACA,WAAW,yBACV;;;;;;;qBAWU,qBAAqB;WACvB,MAAM;EAEf,YAAY,MAAM;;wBAQJ,gBAAgB,gBAAgB,iBAAiB,sBAAmB;wBAMpE,gBAAgB,kBAAe;wBAI/B,kBAAkB,gBAAgB,kBAAe;wBAIjD,YAAY,gBAAgB,kBAAe;;;;;;;;;;wBAmC3C,cAAc,iBAAiB"}
1
+ {"version":3,"file":"respond.d.cts","names":[],"sources":["../../src/auth/respond.ts"],"mappings":";;;;;iBAQiB;EACf;IACE;IACA;IACA;IACA;;;wBAMY,UACd,cACA,gBACA,gBACA,iBACA,WAAW,yBACV;;;;;;;qBAWU,qBAAqB;WACvB,MAAM;EAEf,YAAY,MAAM;;;;;;;wBAaJ,gBAAgB,gBAAgB,iBAAiB,sBAAuB;wBAMxE,gBAAgB,kBAAe;wBAI/B,kBAAkB,gBAAgB,kBAAe;wBAIjD,YAAY,gBAAgB,kBAAe;;;;;;;;;;wBAmC3C,cAAc,iBAAiB"}
@@ -22,6 +22,11 @@ export declare class RequestError extends Error {
22
22
  readonly body: ErrorBody;
23
23
  constructor(body: ErrorBody);
24
24
  }
25
+ /**
26
+ * A malformed request: the `ErrorInfo` with `reason` first, then any further `details` (a
27
+ * `BadRequest` naming the fields a schema refused), so `getErrorInfo` finds the reason whatever
28
+ * else the body carries.
29
+ */
25
30
  export declare function invalidArgument(reason: string, message: string, details?: unknown[]): RequestError;
26
31
  export declare function unauthenticated(message: string): RequestError;
27
32
  export declare function resourceExhausted(reason: string, message: string): RequestError;
@@ -1 +1 @@
1
- {"version":3,"file":"respond.d.mts","names":[],"sources":["../../src/auth/respond.ts"],"mappings":";;;;;iBAQiB;EACf;IACE;IACA;IACA;IACA;;;wBAMY,UACd,cACA,gBACA,gBACA,iBACA,WAAW,yBACV;;;;;;;qBAWU,qBAAqB;WACvB,MAAM;EAEf,YAAY,MAAM;;wBAQJ,gBAAgB,gBAAgB,iBAAiB,sBAAmB;wBAMpE,gBAAgB,kBAAe;wBAI/B,kBAAkB,gBAAgB,kBAAe;wBAIjD,YAAY,gBAAgB,kBAAe;;;;;;;;;;wBAmC3C,cAAc,iBAAiB"}
1
+ {"version":3,"file":"respond.d.mts","names":[],"sources":["../../src/auth/respond.ts"],"mappings":";;;;;iBAQiB;EACf;IACE;IACA;IACA;IACA;;;wBAMY,UACd,cACA,gBACA,gBACA,iBACA,WAAW,yBACV;;;;;;;qBAWU,qBAAqB;WACvB,MAAM;EAEf,YAAY,MAAM;;;;;;;wBAaJ,gBAAgB,gBAAgB,iBAAiB,sBAAuB;wBAMxE,gBAAgB,kBAAe;wBAI/B,kBAAkB,gBAAgB,kBAAe;wBAIjD,YAAY,gBAAgB,kBAAe;;;;;;;;;;wBAmC3C,cAAc,iBAAiB"}
@@ -29,9 +29,14 @@ var RequestError = class RequestError extends Error {
29
29
  Object.setPrototypeOf(this, RequestError.prototype);
30
30
  }
31
31
  };
32
- function invalidArgument(reason, message, details) {
32
+ /**
33
+ * A malformed request: the `ErrorInfo` with `reason` first, then any further `details` (a
34
+ * `BadRequest` naming the fields a schema refused), so `getErrorInfo` finds the reason whatever
35
+ * else the body carries.
36
+ */
37
+ function invalidArgument(reason, message, details = []) {
33
38
  const body = errorBody(400, "INVALID_ARGUMENT", reason, message);
34
- if (details) body.error.details = details;
39
+ body.error.details.push(...details);
35
40
  return new RequestError(body);
36
41
  }
37
42
  function unauthenticated(message) {
@@ -1 +1 @@
1
- {"version":3,"file":"respond.mjs","names":[],"sources":["../../src/auth/respond.ts"],"sourcesContent":["import { OAuth2Error, type OAuth2ErrorType } from '../oauth2/error';\nimport { AuthenticationError } from './error';\n\n/**\n * How the JSON routes answer a failure: a google.rpc error body, as `@shware/http` reads it, with\n * one `ErrorInfo` whose `reason` the client branches on. The redirect flow answers differently\n * (`error=…` on `errorUri`, see `Auth.redirect`), since a page, not a client, reads it.\n */\nexport interface ErrorBody {\n error: {\n code: number;\n status: string;\n message: string;\n details: unknown[];\n };\n}\n\nconst ERROR_INFO = 'type.googleapis.com/google.rpc.ErrorInfo';\n\nexport function errorBody(\n code: number,\n status: string,\n reason: string,\n message: string,\n metadata?: Record<string, string>\n): ErrorBody {\n const info = { '@type': ERROR_INFO, reason, ...(metadata ? { metadata } : {}) };\n return { error: { code, status, message, details: [info] } };\n}\n\n/**\n * A request a route cannot act on, answered as it is: malformed, too soon, not signed in. Thrown\n * by the validation helpers so a route reads as one straight line; `errorResponse` turns it into\n * the response. Unlike `AuthenticationError`, which is about who is signing in, this is about\n * the request itself, so it is not the host's to throw.\n */\nexport class RequestError extends Error {\n readonly body: ErrorBody;\n\n constructor(body: ErrorBody) {\n super(body.error.message);\n this.name = 'RequestError';\n this.body = body;\n Object.setPrototypeOf(this, RequestError.prototype);\n }\n}\n\nexport function invalidArgument(reason: string, message: string, details?: unknown[]) {\n const body = errorBody(400, 'INVALID_ARGUMENT', reason, message);\n if (details) body.error.details = details;\n return new RequestError(body);\n}\n\nexport function unauthenticated(message: string) {\n return new RequestError(errorBody(401, 'UNAUTHENTICATED', 'UNAUTHENTICATED', message));\n}\n\nexport function resourceExhausted(reason: string, message: string) {\n return new RequestError(errorBody(429, 'RESOURCE_EXHAUSTED', reason, message));\n}\n\nexport function unavailable(reason: string, message: string) {\n return new RequestError(errorBody(503, 'UNAVAILABLE', reason, message));\n}\n\n/**\n * What an `OAuth2Error` from the provider client means to the caller of a JSON route: the request\n * named something that does not exist (400), the credential it sent was refused (403), or the\n * provider is down (503). Its message stays in the logs: it can name a client id or quote the\n * provider's response.\n */\nconst OAUTH2_STATUS: Record<OAuth2ErrorType, [code: number, status: string]> = {\n invalid_request: [400, 'INVALID_ARGUMENT'],\n invalid_scope: [400, 'INVALID_ARGUMENT'],\n unsupported_grant_type: [400, 'INVALID_ARGUMENT'],\n unsupported_response_type: [400, 'INVALID_ARGUMENT'],\n redirect_uri_mismatch: [400, 'INVALID_ARGUMENT'],\n invalid_client: [403, 'PERMISSION_DENIED'],\n invalid_grant: [403, 'PERMISSION_DENIED'],\n invalid_token: [403, 'PERMISSION_DENIED'],\n unauthorized_client: [403, 'PERMISSION_DENIED'],\n insufficient_scope: [403, 'PERMISSION_DENIED'],\n access_denied: [403, 'PERMISSION_DENIED'],\n server_error: [503, 'UNAVAILABLE'],\n temporarily_unavailable: [503, 'UNAVAILABLE'],\n};\n\n/**\n * The response a JSON route gives for an error it knows, or `null` for one it does not, which is\n * the host's (a 500). Every JSON route runs under this, so the three kinds of failure have one\n * mapping: a `RequestError` as it is, an `AuthenticationError` as `403 PERMISSION_DENIED` with the\n * reason and metadata (the host's refusal or the SDK's own: a wrong code, a replayed nonce), an\n * `OAuth2Error` by what it means (`OAUTH2_<error>` as the reason). Exported for the host's error\n * handler, so a flow of its own that calls `Auth` directly (`verifyEmailCode`) answers the same way:\n * `errorResponse(error) ?? yourHandler(error)`.\n */\nexport function errorResponse(error: unknown): Response | null {\n if (error instanceof RequestError) {\n return Response.json(error.body, { status: error.body.error.code });\n }\n if (error instanceof AuthenticationError) {\n const body = errorBody(403, 'PERMISSION_DENIED', error.reason, error.message, error.metadata);\n return Response.json(body, { status: body.error.code });\n }\n if (error instanceof OAuth2Error) {\n console.warn('OAuth2 login failed', error);\n const [code, status] = OAUTH2_STATUS[error.error] ?? [503, 'UNAVAILABLE'];\n const reason = `OAUTH2_${error.error.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`;\n const body = errorBody(code, status, reason, `OAuth2 ${error.error}`);\n return Response.json(body, { status: body.error.code });\n }\n return null;\n}\n"],"mappings":";;;AAiBA,MAAM,aAAa;AAEnB,SAAgB,UACd,MACA,QACA,QACA,SACA,UACW;CAEX,OAAO,EAAE,OAAO;EAAE;EAAM;EAAQ;EAAS,SAAS,CAAC;GADpC,SAAS;GAAY;GAAQ,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EACrB,CAAC;CAAE,EAAE;AAC7D;;;;;;;AAQA,IAAa,eAAb,MAAa,qBAAqB,MAAM;CACtC;CAEA,YAAY,MAAiB;EAC3B,MAAM,KAAK,MAAM,OAAO;EACxB,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,aAAa,SAAS;CACpD;AACF;AAEA,SAAgB,gBAAgB,QAAgB,SAAiB,SAAqB;CACpF,MAAM,OAAO,UAAU,KAAK,oBAAoB,QAAQ,OAAO;CAC/D,IAAI,SAAS,KAAK,MAAM,UAAU;CAClC,OAAO,IAAI,aAAa,IAAI;AAC9B;AAEA,SAAgB,gBAAgB,SAAiB;CAC/C,OAAO,IAAI,aAAa,UAAU,KAAK,mBAAmB,mBAAmB,OAAO,CAAC;AACvF;AAEA,SAAgB,kBAAkB,QAAgB,SAAiB;CACjE,OAAO,IAAI,aAAa,UAAU,KAAK,sBAAsB,QAAQ,OAAO,CAAC;AAC/E;AAEA,SAAgB,YAAY,QAAgB,SAAiB;CAC3D,OAAO,IAAI,aAAa,UAAU,KAAK,eAAe,QAAQ,OAAO,CAAC;AACxE;;;;;;;AAQA,MAAM,gBAAyE;CAC7E,iBAAiB,CAAC,KAAK,kBAAkB;CACzC,eAAe,CAAC,KAAK,kBAAkB;CACvC,wBAAwB,CAAC,KAAK,kBAAkB;CAChD,2BAA2B,CAAC,KAAK,kBAAkB;CACnD,uBAAuB,CAAC,KAAK,kBAAkB;CAC/C,gBAAgB,CAAC,KAAK,mBAAmB;CACzC,eAAe,CAAC,KAAK,mBAAmB;CACxC,eAAe,CAAC,KAAK,mBAAmB;CACxC,qBAAqB,CAAC,KAAK,mBAAmB;CAC9C,oBAAoB,CAAC,KAAK,mBAAmB;CAC7C,eAAe,CAAC,KAAK,mBAAmB;CACxC,cAAc,CAAC,KAAK,aAAa;CACjC,yBAAyB,CAAC,KAAK,aAAa;AAC9C;;;;;;;;;;AAWA,SAAgB,cAAc,OAAiC;CAC7D,IAAI,iBAAiB,cACnB,OAAO,SAAS,KAAK,MAAM,MAAM,EAAE,QAAQ,MAAM,KAAK,MAAM,KAAK,CAAC;CAEpE,IAAI,iBAAiB,qBAAqB;EACxC,MAAM,OAAO,UAAU,KAAK,qBAAqB,MAAM,QAAQ,MAAM,SAAS,MAAM,QAAQ;EAC5F,OAAO,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,MAAM,KAAK,CAAC;CACxD;CACA,IAAI,iBAAiB,aAAa;EAChC,QAAQ,KAAK,uBAAuB,KAAK;EACzC,MAAM,CAAC,MAAM,UAAU,cAAc,MAAM,UAAU,CAAC,KAAK,aAAa;EAExE,MAAM,OAAO,UAAU,MAAM,QAAQ,UADZ,MAAM,MAAM,YAAY,CAAC,CAAC,QAAQ,cAAc,GAAG,KAC/B,UAAU,MAAM,OAAO;EACpE,OAAO,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,MAAM,KAAK,CAAC;CACxD;CACA,OAAO;AACT"}
1
+ {"version":3,"file":"respond.mjs","names":[],"sources":["../../src/auth/respond.ts"],"sourcesContent":["import { OAuth2Error, type OAuth2ErrorType } from '../oauth2/error';\nimport { AuthenticationError } from './error';\n\n/**\n * How the JSON routes answer a failure: a google.rpc error body, as `@shware/http` reads it, with\n * one `ErrorInfo` whose `reason` the client branches on. The redirect flow answers differently\n * (`error=…` on `errorUri`, see `Auth.redirect`), since a page, not a client, reads it.\n */\nexport interface ErrorBody {\n error: {\n code: number;\n status: string;\n message: string;\n details: unknown[];\n };\n}\n\nconst ERROR_INFO = 'type.googleapis.com/google.rpc.ErrorInfo';\n\nexport function errorBody(\n code: number,\n status: string,\n reason: string,\n message: string,\n metadata?: Record<string, string>\n): ErrorBody {\n const info = { '@type': ERROR_INFO, reason, ...(metadata ? { metadata } : {}) };\n return { error: { code, status, message, details: [info] } };\n}\n\n/**\n * A request a route cannot act on, answered as it is: malformed, too soon, not signed in. Thrown\n * by the validation helpers so a route reads as one straight line; `errorResponse` turns it into\n * the response. Unlike `AuthenticationError`, which is about who is signing in, this is about\n * the request itself, so it is not the host's to throw.\n */\nexport class RequestError extends Error {\n readonly body: ErrorBody;\n\n constructor(body: ErrorBody) {\n super(body.error.message);\n this.name = 'RequestError';\n this.body = body;\n Object.setPrototypeOf(this, RequestError.prototype);\n }\n}\n\n/**\n * A malformed request: the `ErrorInfo` with `reason` first, then any further `details` (a\n * `BadRequest` naming the fields a schema refused), so `getErrorInfo` finds the reason whatever\n * else the body carries.\n */\nexport function invalidArgument(reason: string, message: string, details: unknown[] = []) {\n const body = errorBody(400, 'INVALID_ARGUMENT', reason, message);\n body.error.details.push(...details);\n return new RequestError(body);\n}\n\nexport function unauthenticated(message: string) {\n return new RequestError(errorBody(401, 'UNAUTHENTICATED', 'UNAUTHENTICATED', message));\n}\n\nexport function resourceExhausted(reason: string, message: string) {\n return new RequestError(errorBody(429, 'RESOURCE_EXHAUSTED', reason, message));\n}\n\nexport function unavailable(reason: string, message: string) {\n return new RequestError(errorBody(503, 'UNAVAILABLE', reason, message));\n}\n\n/**\n * What an `OAuth2Error` from the provider client means to the caller of a JSON route: the request\n * named something that does not exist (400), the credential it sent was refused (403), or the\n * provider is down (503). Its message stays in the logs: it can name a client id or quote the\n * provider's response.\n */\nconst OAUTH2_STATUS: Record<OAuth2ErrorType, [code: number, status: string]> = {\n invalid_request: [400, 'INVALID_ARGUMENT'],\n invalid_scope: [400, 'INVALID_ARGUMENT'],\n unsupported_grant_type: [400, 'INVALID_ARGUMENT'],\n unsupported_response_type: [400, 'INVALID_ARGUMENT'],\n redirect_uri_mismatch: [400, 'INVALID_ARGUMENT'],\n invalid_client: [403, 'PERMISSION_DENIED'],\n invalid_grant: [403, 'PERMISSION_DENIED'],\n invalid_token: [403, 'PERMISSION_DENIED'],\n unauthorized_client: [403, 'PERMISSION_DENIED'],\n insufficient_scope: [403, 'PERMISSION_DENIED'],\n access_denied: [403, 'PERMISSION_DENIED'],\n server_error: [503, 'UNAVAILABLE'],\n temporarily_unavailable: [503, 'UNAVAILABLE'],\n};\n\n/**\n * The response a JSON route gives for an error it knows, or `null` for one it does not, which is\n * the host's (a 500). Every JSON route runs under this, so the three kinds of failure have one\n * mapping: a `RequestError` as it is, an `AuthenticationError` as `403 PERMISSION_DENIED` with the\n * reason and metadata (the host's refusal or the SDK's own: a wrong code, a replayed nonce), an\n * `OAuth2Error` by what it means (`OAUTH2_<error>` as the reason). Exported for the host's error\n * handler, so a flow of its own that calls `Auth` directly (`verifyEmailCode`) answers the same way:\n * `errorResponse(error) ?? yourHandler(error)`.\n */\nexport function errorResponse(error: unknown): Response | null {\n if (error instanceof RequestError) {\n return Response.json(error.body, { status: error.body.error.code });\n }\n if (error instanceof AuthenticationError) {\n const body = errorBody(403, 'PERMISSION_DENIED', error.reason, error.message, error.metadata);\n return Response.json(body, { status: body.error.code });\n }\n if (error instanceof OAuth2Error) {\n console.warn('OAuth2 login failed', error);\n const [code, status] = OAUTH2_STATUS[error.error] ?? [503, 'UNAVAILABLE'];\n const reason = `OAUTH2_${error.error.toUpperCase().replace(/[^A-Z0-9]/g, '_')}`;\n const body = errorBody(code, status, reason, `OAuth2 ${error.error}`);\n return Response.json(body, { status: body.error.code });\n }\n return null;\n}\n"],"mappings":";;;AAiBA,MAAM,aAAa;AAEnB,SAAgB,UACd,MACA,QACA,QACA,SACA,UACW;CAEX,OAAO,EAAE,OAAO;EAAE;EAAM;EAAQ;EAAS,SAAS,CAAC;GADpC,SAAS;GAAY;GAAQ,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EACrB,CAAC;CAAE,EAAE;AAC7D;;;;;;;AAQA,IAAa,eAAb,MAAa,qBAAqB,MAAM;CACtC;CAEA,YAAY,MAAiB;EAC3B,MAAM,KAAK,MAAM,OAAO;EACxB,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,OAAO,eAAe,MAAM,aAAa,SAAS;CACpD;AACF;;;;;;AAOA,SAAgB,gBAAgB,QAAgB,SAAiB,UAAqB,CAAC,GAAG;CACxF,MAAM,OAAO,UAAU,KAAK,oBAAoB,QAAQ,OAAO;CAC/D,KAAK,MAAM,QAAQ,KAAK,GAAG,OAAO;CAClC,OAAO,IAAI,aAAa,IAAI;AAC9B;AAEA,SAAgB,gBAAgB,SAAiB;CAC/C,OAAO,IAAI,aAAa,UAAU,KAAK,mBAAmB,mBAAmB,OAAO,CAAC;AACvF;AAEA,SAAgB,kBAAkB,QAAgB,SAAiB;CACjE,OAAO,IAAI,aAAa,UAAU,KAAK,sBAAsB,QAAQ,OAAO,CAAC;AAC/E;AAEA,SAAgB,YAAY,QAAgB,SAAiB;CAC3D,OAAO,IAAI,aAAa,UAAU,KAAK,eAAe,QAAQ,OAAO,CAAC;AACxE;;;;;;;AAQA,MAAM,gBAAyE;CAC7E,iBAAiB,CAAC,KAAK,kBAAkB;CACzC,eAAe,CAAC,KAAK,kBAAkB;CACvC,wBAAwB,CAAC,KAAK,kBAAkB;CAChD,2BAA2B,CAAC,KAAK,kBAAkB;CACnD,uBAAuB,CAAC,KAAK,kBAAkB;CAC/C,gBAAgB,CAAC,KAAK,mBAAmB;CACzC,eAAe,CAAC,KAAK,mBAAmB;CACxC,eAAe,CAAC,KAAK,mBAAmB;CACxC,qBAAqB,CAAC,KAAK,mBAAmB;CAC9C,oBAAoB,CAAC,KAAK,mBAAmB;CAC7C,eAAe,CAAC,KAAK,mBAAmB;CACxC,cAAc,CAAC,KAAK,aAAa;CACjC,yBAAyB,CAAC,KAAK,aAAa;AAC9C;;;;;;;;;;AAWA,SAAgB,cAAc,OAAiC;CAC7D,IAAI,iBAAiB,cACnB,OAAO,SAAS,KAAK,MAAM,MAAM,EAAE,QAAQ,MAAM,KAAK,MAAM,KAAK,CAAC;CAEpE,IAAI,iBAAiB,qBAAqB;EACxC,MAAM,OAAO,UAAU,KAAK,qBAAqB,MAAM,QAAQ,MAAM,SAAS,MAAM,QAAQ;EAC5F,OAAO,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,MAAM,KAAK,CAAC;CACxD;CACA,IAAI,iBAAiB,aAAa;EAChC,QAAQ,KAAK,uBAAuB,KAAK;EACzC,MAAM,CAAC,MAAM,UAAU,cAAc,MAAM,UAAU,CAAC,KAAK,aAAa;EAExE,MAAM,OAAO,UAAU,MAAM,QAAQ,UADZ,MAAM,MAAM,YAAY,CAAC,CAAC,QAAQ,cAAc,GAAG,KAC/B,UAAU,MAAM,OAAO;EACpE,OAAO,SAAS,KAAK,MAAM,EAAE,QAAQ,KAAK,MAAM,KAAK,CAAC;CACxD;CACA,OAAO;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shware/security",
3
- "version": "9.2.1",
3
+ "version": "9.2.2",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",