@kubun/provider-google 0.16.0 → 0.17.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.
package/lib/api.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ export type GoogleErrorBody = {
2
+ message: string;
3
+ status?: string;
4
+ };
5
+ export type GoogleAPIFailure = {
6
+ httpStatus: number;
7
+ message: string;
8
+ googleStatus?: string;
9
+ };
10
+ export type GoogleAPIClientConfig = {
11
+ api: string;
12
+ accessToken: string;
13
+ fetch?: typeof globalThis.fetch;
14
+ toError: (failure: GoogleAPIFailure) => Error;
15
+ };
16
+ export type GoogleAPIGetOptions = {
17
+ signal?: AbortSignal;
18
+ };
19
+ export type GoogleAPISendOptions = {
20
+ method: string;
21
+ body?: unknown;
22
+ headers?: Record<string, string>;
23
+ signal?: AbortSignal;
24
+ };
25
+ export type GoogleAPIClient = {
26
+ get<T>(url: string, options?: GoogleAPIGetOptions): Promise<T>;
27
+ send<T>(url: string, options: GoogleAPISendOptions): Promise<T>;
28
+ request(url: string, options?: GoogleAPISendOptions): Promise<Response>;
29
+ fail(response: Response): Promise<never>;
30
+ };
31
+ export declare function parseGoogleErrorBody(response: Response): Promise<GoogleErrorBody>;
32
+ export declare function createGoogleAPIClient(config: GoogleAPIClientConfig): GoogleAPIClient;
package/lib/api.js ADDED
@@ -0,0 +1,61 @@
1
+ export async function parseGoogleErrorBody(response) {
2
+ try {
3
+ const body = await response.json();
4
+ return {
5
+ message: body.error?.message ?? `${response.status} ${response.statusText}`,
6
+ status: body.error?.status
7
+ };
8
+ } catch {
9
+ return {
10
+ message: `${response.status} ${response.statusText}`
11
+ };
12
+ }
13
+ }
14
+ export function createGoogleAPIClient(config) {
15
+ const fetchFn = config.fetch ?? globalThis.fetch;
16
+ async function request(url, options) {
17
+ return fetchFn(url, {
18
+ ...options?.method != null ? {
19
+ method: options.method
20
+ } : {},
21
+ headers: {
22
+ Authorization: `Bearer ${config.accessToken}`,
23
+ ...options?.body !== undefined ? {
24
+ 'Content-Type': 'application/json'
25
+ } : {},
26
+ ...options?.headers
27
+ },
28
+ ...options?.body !== undefined ? {
29
+ body: JSON.stringify(options.body)
30
+ } : {},
31
+ signal: options?.signal
32
+ });
33
+ }
34
+ async function fail(response) {
35
+ const detail = await parseGoogleErrorBody(response);
36
+ throw config.toError({
37
+ httpStatus: response.status,
38
+ message: `${config.api} error: ${detail.message}`,
39
+ googleStatus: detail.status
40
+ });
41
+ }
42
+ async function get(url, options) {
43
+ const response = await request(url, {
44
+ method: 'GET',
45
+ signal: options?.signal
46
+ });
47
+ if (!response.ok) return fail(response);
48
+ return await response.json();
49
+ }
50
+ async function send(url, options) {
51
+ const response = await request(url, options);
52
+ if (!response.ok) return fail(response);
53
+ return await response.json();
54
+ }
55
+ return {
56
+ get,
57
+ send,
58
+ request,
59
+ fail
60
+ };
61
+ }
package/lib/index.d.ts CHANGED
@@ -1,7 +1,15 @@
1
- import type { OAuthProviderDefinition } from '@kubun/credential-types';
1
+ import type { OAuthProviderDefinition } from '@kokuin/oauth';
2
+ export { createGoogleAPIClient, type GoogleAPIClient, type GoogleAPIClientConfig, type GoogleAPIFailure, type GoogleAPIGetOptions, type GoogleAPISendOptions, type GoogleErrorBody, parseGoogleErrorBody, } from './api.js';
3
+ export declare const googleAuthorizationParams: Record<string, string>;
2
4
  type CreateGoogleProviderParams = {
5
+ mode: 'confidential';
3
6
  clientID: string;
4
7
  clientSecret: string;
8
+ } | {
9
+ mode: 'native';
10
+ clientID: string;
11
+ clientSecret?: string;
12
+ };
13
+ export declare function createGoogleProvider(params: CreateGoogleProviderParams): OAuthProviderDefinition & {
14
+ authorizationParams?: Record<string, string>;
5
15
  };
6
- export declare function createGoogleProvider(params: CreateGoogleProviderParams): OAuthProviderDefinition;
7
- export {};
package/lib/index.js CHANGED
@@ -1,11 +1,19 @@
1
+ export { createGoogleAPIClient, parseGoogleErrorBody } from './api.js';
2
+ export const googleAuthorizationParams = {
3
+ // Offline access requests a refresh token (issuance stays provider-dependent);
4
+ // consent keeps that guarantee for repeat authorizations. select_account forces
5
+ // the account chooser, avoiding the multi-account authuser dead-end.
6
+ access_type: 'offline',
7
+ prompt: 'select_account consent'
8
+ };
1
9
  export function createGoogleProvider(params) {
2
10
  if (!params.clientID) {
3
11
  throw new Error('Google provider requires a non-empty clientID');
4
12
  }
5
- if (!params.clientSecret) {
6
- throw new Error('Google provider requires a non-empty clientSecret');
13
+ if (params.mode === 'confidential' && !params.clientSecret) {
14
+ throw new Error('A confidential Google provider requires a non-empty clientSecret');
7
15
  }
8
- return {
16
+ const base = {
9
17
  name: 'google',
10
18
  authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
11
19
  tokenEndpoint: 'https://oauth2.googleapis.com/token',
@@ -14,7 +22,19 @@ export function createGoogleProvider(params) {
14
22
  'profile',
15
23
  'email'
16
24
  ],
25
+ authorizationParams: googleAuthorizationParams
26
+ };
27
+ return params.mode === 'confidential' ? {
28
+ ...base,
29
+ mode: 'confidential',
17
30
  clientID: params.clientID,
18
31
  clientSecret: params.clientSecret
32
+ } : {
33
+ ...base,
34
+ mode: 'native',
35
+ clientID: params.clientID,
36
+ ...params.clientSecret ? {
37
+ clientSecret: params.clientSecret
38
+ } : {}
19
39
  };
20
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubun/provider-google",
3
- "version": "0.16.0",
3
+ "version": "0.17.1",
4
4
  "keywords": [],
5
5
  "license": "see LICENSE.md",
6
6
  "sideEffects": false,
@@ -15,7 +15,7 @@
15
15
  "LICENSE.md"
16
16
  ],
17
17
  "dependencies": {
18
- "@kubun/credential-types": "^0.16.0"
18
+ "@kokuin/oauth": "^0.1.1"
19
19
  },
20
20
  "publishConfig": {
21
21
  "access": "public"
@@ -23,8 +23,8 @@
23
23
  "scripts": {
24
24
  "build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
25
25
  "build:clean": "del lib",
26
- "build:js": "swc src -d ./lib --config-file ../../node_modules/@kigu/dev/swc.json --strip-leading-paths",
27
- "build:types": "tsc --emitDeclarationOnly --skipLibCheck",
26
+ "build:js": "del 'lib/**/*.js' && swc src -d ./lib --config-file ../../node_modules/@kigu/dev/swc.json --strip-leading-paths",
27
+ "build:types": "del 'lib/**/*.d.ts' 'lib/**/*.d.ts.map' && tsc --emitDeclarationOnly --skipLibCheck",
28
28
  "build:types:ci": "tsc --emitDeclarationOnly --declarationMap false",
29
29
  "test": "pnpm run test:types && pnpm run test:unit",
30
30
  "test:types": "tsc --noEmit -p tsconfig.test.json",