Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add configuration for jsr.io #76

Merged
merged 2 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ on:
jobs:
publish:
runs-on: ubuntu-latest

permissions:
contents: read
id-token: write

steps:
- name: Checkout 🛎️
uses: actions/checkout@v4
Expand Down Expand Up @@ -43,7 +48,12 @@ jobs:
pnpm -r publish --no-git-checks --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}


- name: Publish 🚀 PRODUCTION on JSR.io
if: '!github.event.release.prerelease'
run: |
pnpm --filter '*' jsr:publish

- name: Post to a Slack channel
id: slack
uses: slackapi/slack-github-action@v1.25.0
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
"make:version": "lerna version --no-private",
"example:cjs": "pnpm --filter cjs start",
"example:esm": "pnpm --filter esm start",
"example:esm:serve": "pnpm --filter esm serve"
"example:esm:serve": "pnpm --filter esm serve",
"version": "node update-jsr-version.js && git add ."
},
"devDependencies": {
"@commercelayer/eslint-config-ts": "^1.3.0",
"husky": "^9.0.11",
"lerna": "^8.1.2",
"replace-in-file": "^7.1.0",
"typescript": "^5.4.2"
}
}
2 changes: 1 addition & 1 deletion packages/js-auth/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Commerce Layer JS Auth

A JavaScript Library wrapper that helps you use the Commerce Layer API for [Authentication](https://docs.commercelayer.io/developers/authentication).
A JavaScript library designed to simplify [authentication](https://docs.commercelayer.io/developers/authentication) when interacting with the Commerce Layer API.

## What is Commerce Layer?

Expand Down
5 changes: 5 additions & 0 deletions packages/js-auth/jsr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "@commercelayer/js-auth",
"version": "6.0.1",
"exports": "./src/index.ts"
}
5 changes: 3 additions & 2 deletions packages/js-auth/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@commercelayer/js-auth",
"version": "6.0.1",
"description": "Commerce Layer Javascript Auth",
"description": "A JavaScript library designed to simplify authentication when interacting with the Commerce Layer API.",
"repository": {
"url": "https://github.com/commercelayer/commercelayer-js-auth.git"
},
Expand Down Expand Up @@ -37,7 +37,8 @@
"lint:fix": "eslint src --ext .ts,.tsx --fix",
"test": "pnpm run lint && vitest run --silent",
"test:watch": "vitest --silent",
"build": "tsup"
"build": "tsup",
"jsr:publish": "pnpm dlx jsr publish"
},
"publishConfig": {
"access": "public"
Expand Down
45 changes: 36 additions & 9 deletions packages/js-auth/src/authenticate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,46 @@ import type {
GrantType,
AuthenticateOptions,
AuthenticateReturn
} from '#types/index.js'
} from './types/index.js'

import { camelCaseToSnakeCase } from '#utils/camelCaseToSnakeCase.js'
import { mapKeys } from '#utils/mapKeys.js'
import { snakeCaseToCamelCase } from '#utils/snakeCaseToCamelCase.js'
import { camelCaseToSnakeCase } from './utils/camelCaseToSnakeCase.js'
import { mapKeys } from './utils/mapKeys.js'
import { snakeCaseToCamelCase } from './utils/snakeCaseToCamelCase.js'

interface TokenJson {
expires: Date
expires_in: number
[key: string]: string | number | Date
}

export async function authenticate<G extends GrantType>(
grantType: G,
{ domain = 'commercelayer.io', headers, ...options }: AuthenticateOptions<G>
): Promise<AuthenticateReturn<G>> {
/**
* Authenticate helper used to get the access token.
*
* _Please note that the authentication endpoint is subject to a [rate limit](https://docs.commercelayer.io/core/rate-limits)
* of **max 30 reqs / 1 min** both in live and test mode._
* @param grantType The type of OAuth 2.0 grant being used for authentication.
* @param options Authenticate options
* @returns
* @example
* ```ts
* import { authenticate } from '@commercelayer/js-auth'
*
* const auth = await authenticate('client_credentials', {
* clientId: '{{ clientId }}',
* scope: 'market:id:DGzAouppwn'
* })
*
* console.log(auth.accessToken)
* ```
*/
export async function authenticate<TGrantType extends GrantType>(
grantType: TGrantType,
{
domain = 'commercelayer.io',
headers,
...options
}: AuthenticateOptions<TGrantType>
): Promise<AuthenticateReturn<TGrantType>> {
const body = mapKeys(
{
grant_type: grantType,
Expand All @@ -39,5 +63,8 @@ export async function authenticate<G extends GrantType>(
const json: TokenJson = await response.json()
json.expires = new Date(Date.now() + json.expires_in * 1000)

return mapKeys(json, snakeCaseToCamelCase) as unknown as AuthenticateReturn<G>
return mapKeys(
json,
snakeCaseToCamelCase
) as unknown as AuthenticateReturn<TGrantType>
}
27 changes: 26 additions & 1 deletion packages/js-auth/src/jwtDecode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { decodeBase64URLSafe } from '#utils/base64.js'
import { decodeBase64URLSafe } from './utils/base64.js'

/**
* Decode a Commerce Layer access token.
Expand Down Expand Up @@ -133,24 +133,49 @@ type JWTIntegration = JWTOrganizationBase & {
}
}

/**
* Checks if the provided payload represents a `user`.
* @param payload The payload to be checked.
* @returns
*/
export function jwtIsUser(payload: Payload): payload is JWTUser {
return payload.application.kind === 'user'
}

/**
* Checks if the provided payload represents a `dashboard`.
* @param payload The payload to be checked.
* @returns
*/
export function jwtIsDashboard(payload: Payload): payload is JWTDashboard {
return payload.application.kind === 'dashboard'
}

/**
* Checks if the provided payload represents an `integration`.
* @param payload The payload to be checked.
* @returns
*/
export function jwtIsIntegration(payload: Payload): payload is JWTIntegration {
return payload.application.kind === 'integration'
}

/**
* Checks if the provided payload represents a `sales_channel`.
* @param payload The payload to be checked.
* @returns
*/
export function jwtIsSalesChannel(
payload: Payload
): payload is JWTSalesChannel {
return payload.application.kind === 'sales_channel'
}

/**
* Checks if the provided payload represents a `webapp`.
* @param payload The payload to be checked.
* @returns
*/
export function jwtIsWebApp(payload: Payload): payload is JWTWebApp {
return payload.application.kind === 'webapp'
}
2 changes: 1 addition & 1 deletion packages/js-auth/src/jwtEncode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { encodeBase64URLSafe } from '#utils/base64.js'
import { encodeBase64URLSafe } from './utils/base64.js'

interface Owner {
type: 'User' | 'Customer'
Expand Down
20 changes: 17 additions & 3 deletions packages/js-auth/src/revoke.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
import type { RevokeOptions, RevokeReturn } from '#types/index.js'
import type { RevokeOptions, RevokeReturn } from './types/index.js'

import { camelCaseToSnakeCase } from '#utils/camelCaseToSnakeCase.js'
import { mapKeys } from '#utils/mapKeys.js'
import { camelCaseToSnakeCase } from './utils/camelCaseToSnakeCase.js'
import { mapKeys } from './utils/mapKeys.js'

/**
* Revoke a previously generated access token (refresh tokens included) before its natural expiration date.
*
* @param options Revoke options
* @returns
* @example
* ```ts
* await revoke({
* clientId: '{{ integrationClientId }}',
* clientSecret: '{{ integrationClientSecret }}',
* token: authenticateResponse.accessToken
* })
* ```
*/
export async function revoke({
domain = 'commercelayer.io',
...options
Expand Down
11 changes: 10 additions & 1 deletion packages/js-auth/src/types/authorizationCode.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import type { TBaseOptions } from '#types/base.js'
import type { TBaseOptions } from './base.js'
import type { TPasswordReturn } from './password.js'

/**
* The authorization code grant type is used by clients to exchange an authorization code for an access token.
* @see https://docs.commercelayer.io/core/authentication/authorization-code#getting-an-access-token
*/
export interface TAuthorizationCodeOptions extends TBaseOptions {
/**
* The authorization code that [you got](https://docs.commercelayer.io/core/authentication/authorization-code#getting-an-authorization-code) from the redirect URI query string.
*/
code: string
/**
* Your application's redirect URI.
*/
redirectUri: string
/**
* Your application's client secret.
*/
clientSecret: string
}

Expand Down
6 changes: 5 additions & 1 deletion packages/js-auth/src/types/clientCredentials.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import type { TBaseOptions } from '#types/base.js'
import type { TBaseOptions } from './base.js'

/**
* The client credentials grant type is used by clients to obtain an access token outside of the context of a user.
* @see https://docs.commercelayer.io/core/authentication/client-credentials
*/
export interface TClientCredentialsOptions extends TBaseOptions {
/**
* Your application's client secret
* (required for [confidential](https://docs.commercelayer.io/core/authentication/client-credentials#integration) API credentials).
*/
clientSecret?: string
}
6 changes: 5 additions & 1 deletion packages/js-auth/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { TPasswordOptions, TPasswordReturn } from './password.js'
import type { TRefreshTokenOptions } from './refreshToken.js'

/**
* The grant type.
* The type of OAuth 2.0 grant being used for authentication.
*/
export type GrantType =
| 'password'
Expand All @@ -18,6 +18,7 @@ export type GrantType =
| 'authorization_code'
| 'urn:ietf:params:oauth:grant-type:jwt-bearer'

/** The options type for the `authenticate` helper. */
export type AuthenticateOptions<TGrantType extends GrantType> =
TGrantType extends 'urn:ietf:params:oauth:grant-type:jwt-bearer'
? TJwtBearerOptions
Expand All @@ -31,6 +32,7 @@ export type AuthenticateOptions<TGrantType extends GrantType> =
? TAuthorizationCodeOptions
: never

/** The return type of the `authenticate` helper. */
export type AuthenticateReturn<TGrantType extends GrantType> =
TGrantType extends 'urn:ietf:params:oauth:grant-type:jwt-bearer'
? TJwtBearerReturn
Expand All @@ -44,11 +46,13 @@ export type AuthenticateReturn<TGrantType extends GrantType> =
? TAuthorizationCodeReturn
: never

/** The options type for the `revoke` helper. */
export type RevokeOptions = Pick<TBaseOptions, 'clientId' | 'domain'> & {
/** Your application's client secret (required for confidential API credentials and non-confidential API credentials without a customer or a user in the JWT only). */
clientSecret?: string
/** A valid access or refresh token. */
token: string
}

/** The return type of the `revoke` helper. */
export type RevokeReturn = Pick<TError, 'errors'>
2 changes: 1 addition & 1 deletion packages/js-auth/src/types/jwtBearer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TBaseOptions } from '#types/base.js'
import type { TBaseOptions } from './base.js'
import type { TPasswordReturn } from './password.js'

/**
Expand Down
4 changes: 3 additions & 1 deletion packages/js-auth/src/types/password.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type { TBaseOptions, TBaseReturn } from '#types/base.js'
import type { TBaseOptions, TBaseReturn } from './base.js'

/**
* The password grant type is used by first-party clients to exchange a user's credentials for an access token.
* @see https://docs.commercelayer.io/core/authentication/password
*/
export interface TPasswordOptions extends TBaseOptions {
/** The customer's email address. */
username: string
/** The customer's password */
password: string
}

Expand Down
9 changes: 8 additions & 1 deletion packages/js-auth/src/types/refreshToken.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import type { TBaseOptions } from '#types/base.js'
import type { TBaseOptions } from './base.js'

/**
* The refresh token grant type is used by clients to exchange a refresh token for an access token when the access token has expired.
* @see https://docs.commercelayer.io/core/authentication/refresh-token
*/
export interface TRefreshTokenOptions extends TBaseOptions {
/**
* A valid `refresh_token`.
*/
refreshToken: string
/**
* Your application's client secret
* (required for confidential API credentials — i.e. in case of [authorization code flow](https://docs.commercelayer.io/core/authentication/refresh-token#webapp-application-with-authorization-code-flow)).
*/
clientSecret?: string
}
5 changes: 0 additions & 5 deletions packages/js-auth/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@
"noPropertyAccessFromIndexSignature": true /* Require undeclared properties from index signatures to use element accesses. */,
"types": ["vitest/globals"],
"baseUrl": "." /* Base directory to resolve non-absolute module names. */,
"paths": {
"#utils/*": ["src/utils/*"],
"#types/*": ["src/types/*"],
"#types": ["src/types/index"]
},
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
Expand Down
15 changes: 14 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading