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

feat: initialization #6

Merged
merged 24 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2f0303b
chore(tsconfig): update compiler options and paths
Convly Nov 29, 2024
29a2c0b
docs(README): update SDK usage for JavaScript/TypeScript projects
Convly Nov 29, 2024
9bf822b
test(jest): configure coverage thresholds and ignore patterns
Convly Nov 29, 2024
ade6270
chore(commitlint): reorder import statements
Convly Nov 29, 2024
90a1fdb
chore(git): update ignore files for compressed and config dirs
Convly Nov 29, 2024
d74ef5e
chore(eslint): migrate config to mjs module format
Convly Nov 29, 2024
6919606
chore(scripts): add pre-pack script for checks and build
Convly Nov 29, 2024
0ab754c
feat(auth): add base types and abstract class for providers
Convly Nov 29, 2024
17073b4
feat(auth): add new API-token and users-permissions providers
Convly Nov 29, 2024
fd37281
feat(auth): add authentication provider factory with type definitions
Convly Nov 29, 2024
8cbe76f
feat(auth): add authentication manager with strategy support
Convly Nov 29, 2024
7d7a185
feat(validators): add URL and SDK validation components
Convly Nov 29, 2024
711f3ba
feat(http): add initial HttpClient implementation with auth and url v…
Convly Nov 29, 2024
0dcb4f2
feat(sdk): implement Strapi SDK
Convly Nov 29, 2024
3cd4bb6
test: add unit tests for full coverage
Convly Nov 29, 2024
61a10e0
Merge branch 'main' of github.com:strapi/sdk-js into feat/sdk-initial…
Convly Nov 29, 2024
e611b87
chore(workflows): fix style
Convly Dec 2, 2024
82f37b6
test(sdk): remove initialization tests and refactor url validation tests
Convly Dec 2, 2024
9f0ffce
chore(url): remove protocol validation logic
Convly Dec 2, 2024
f20fd14
fix: pr review typos, always prepend api to baseurl and make package …
jhoward1994 Dec 4, 2024
935d16f
fix: expect content api url as baseurl
jhoward1994 Dec 5, 2024
711e9ea
chore: revert type module
jhoward1994 Dec 5, 2024
ad8fb94
chore: mark users and permissions auth as experimental
jhoward1994 Dec 5, 2024
6b45bc9
Merge pull request #8 from strapi/fix/module-imports
Convly Dec 5, 2024
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
3 changes: 2 additions & 1 deletion .commitlintrc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { UserConfig } from '@commitlint/types';
import { RuleConfigSeverity } from '@commitlint/types';

import type { UserConfig } from '@commitlint/types';

const config: UserConfig = {
extends: ['@commitlint/config-conventional'],
rules: {
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/issues_handleLabel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Issue Labeled

on:
issues:
types: [ labeled ]
types: [labeled]

permissions:
issues: write
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ jobs:

unit_back:
name: 'unit_back (node: ${{ matrix.node }})'
needs: [ cache-and-install, build ]
needs: [cache-and-install, build]
runs-on: ubuntu-latest
strategy:
matrix:
node: [ 20, 22 ]
node: [20, 22]
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ $RECYCLE.BIN/
*.jar
*.rar
*.tar
*.tgz
*.zip
*.com
*.class
Expand Down
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<h1 align="center">sdk-js</h1>
<h3 align="center">An SDK you can use to easily interface with Strapi from your javascript project</h3>
<h3 align="center">An SDK you can use to easily interface with Strapi from your JavaScript and TypeScript projects</h3>

<br />

Expand All @@ -21,13 +21,14 @@ sdk-js is an SDK you can use to easily interface with Strapi from your JavaScrip

## Getting Started With Strapi

If you're brand new to Strapi development, we recommend you follow the [Strapi Quick Start Guide](https://docs.strapi.io/dev-docs/quick-start)
If you're brand new to Strapi development, it is recommended to follow the [Strapi Quick Start Guide](https://docs.strapi.io/dev-docs/quick-start)

sdk-js is compatible with Strapi v5+ and interfaces with Strapi's REST API. You can read the API docs [here](https://docs.strapi.io/dev-docs/api/rest)

## SDK Purpose

sdk-js is the recommended and easiest way to interface with Strapi from your javascript project. It allows you to easily create, read, update, and delete Strapi content through strongly typed methods.
sdk-js is the recommended and easiest way to interface with Strapi from your JavaScript and TypeScript projects.
It allows you to easily create, read, update, and delete Strapi content through strongly typed methods.

<!-- TODO confirm whether this is done in MVP -->

Expand All @@ -42,11 +43,11 @@ In its simplest form, "@strapi/sdk-js" works by being connected to the URL of yo
### Importing the SDK

```js
import { createSDK } from '@strapi/sdk-js'; // ES Modules
// const { createSDK } = require("@strapi/sdk-js"); CommonJS
import { createStrapiSDK } from '@strapi/sdk-js'; // ES Modules
// const { createStrapiSDK } = require("@strapi/sdk-js"); CommonJS

const strapiSDK = createSDK({
url: 'http://localhost:1337',
const strapiSDK = createStrapiSDK({
baseURL: 'http://localhost:1337',
});
```

Expand All @@ -55,8 +56,8 @@ const strapiSDK = createSDK({
```html
<script src="https://cdn.jsdelivr.net/npm/@strapi/sdk-js"></script>
<script>
const strapiSDK = createSDK({
url: 'http://localhost:1337',
const strapiSDK = createStrapiSDK({
baseURL: 'http://localhost:1337',
});
</script>
```
Expand Down Expand Up @@ -89,12 +90,12 @@ As opposed to importing the SDK from a CDN or NPM, the generated asset can then
Alternatively, you can use the SDK from a CDN or NPM, but provide the SDK with a Strapi schema.

```js
import { createSDK } from '@strapi/sdk-js';
import { createStrapiSDK } from '@strapi/sdk-js';
// TODO clarify where this comes from and how to generate it
import strapiAppSchema from '../path/to/strapi-app-schema.json';

const strapiSDK = createSDK({
url: 'http://localhost:1337',
const strapiSDK = createStrapiSDK({
baseURL: 'http://localhost:1337',
schema: strapiAppSchema,
});
```
Expand Down
24 changes: 0 additions & 24 deletions eslint.config.js

This file was deleted.

49 changes: 49 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import pluginEslintImport from 'eslint-plugin-import';
import pluginTypescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';

export default {
languageOptions: {
parser: tsParser,
parserOptions: {
project: ['./tsconfig.eslint.json'],
},
},
files: ['{src,tests}/**/*.{js,ts,jsx,tsx,yml,yaml}'],
plugins: {
'@typescript-eslint': pluginTypescriptEslint,
import: pluginEslintImport,
},
rules: {
// Use the TypeScript port of 'no-unused-vars' to prevent false positives on abstract methods parameters
// while keeping consistency with TS native behavior of ignoring parameters starting with '_'.
// https://typescript-eslint.io/rules/no-unused-vars/
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'all',
argsIgnorePattern: '^_',
caughtErrors: 'all',
caughtErrorsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
varsIgnorePattern: '^_',
ignoreRestSiblings: true,
},
],

// eslint-plugin-import
'import/no-default-export': 'error',
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
'import/first': ['error'],
'import/exports-last': ['error'],
'import/order': [
'error',
{
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
'newlines-between': 'always',
alphabetize: { order: 'asc', caseInsensitive: true },
},
],
},
};
10 changes: 10 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
/** @type {import('ts-jest').JestConfigWithTsJest} **/
module.exports = {
rootDir: '.',
testEnvironment: 'node',
testMatch: ['<rootDir>/tests/unit/**/*.test.ts'],
transform: {
'^.+.tsx?$': ['ts-jest', {}],
},
coverageDirectory: '<rootDir>/.coverage/',
coveragePathIgnorePatterns: ['/node_modules/', '/tests/'],
coverageThreshold: {
global: {
branches: 95,
functions: 95,
lines: 95,
statements: 95,
},
},
};
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
},
"./package.json": "./package.json"
},
"files": [],
"files": [
"./package.json",
"dist/"
],
"scripts": {
"build": "rollup --config rollup.config.mjs --failAfterWarnings",
"build:clean": "rollup --config rollup.config.mjs --failAfterWarnings",
Expand All @@ -45,7 +48,8 @@
"test": "jest --verbose",
"test:cov": "jest --verbose --coverage",
"ts:check": "tsc -p tsconfig.build.json --noEmit",
"watch": "rollup --config rollup.config.mjs --watch --failAfterWarnings"
"watch": "rollup --config rollup.config.mjs --watch --failAfterWarnings",
"prepack": "pnpm exec ./scripts/pre-pack.sh"
},
"devDependencies": {
"@commitlint/cli": "19.6.0",
Expand Down
16 changes: 16 additions & 0 deletions scripts/pre-pack.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh

# Run the Prettier check
pnpm prettier:check &&

# Run linting
pnpm lint &&

# Run TypeScript type check
pnpm ts:check &&

# Run tests with coverage
pnpm test:cov &&

# Run the clean build
pnpm build:clean
83 changes: 83 additions & 0 deletions src/auth/factory/factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { StrapiSDKError } from '../../errors';

import type { AuthProviderCreator, AuthProviderMap, CreateAuthProviderParams } from './types';
import type { AuthProvider } from '../providers';

/**
* A factory class responsible for creating and managing authentication providers.
*
* It facilitates the registration and creation of different authentication
* strategies which implement the AuthProvider interface.
*
* @template T_Providers Defines a map for authentication strategy names to their corresponding creator functions.
*/
export class AuthProviderFactory<T_Providers extends AuthProviderMap = {}> {
private readonly _registry = new Map<StringKeysOf<T_Providers>, AuthProviderCreator>();

/**
* Creates an instance of an authentication provider based on the specified strategy.
*
* @param authStrategy The authentication strategy name to be used for creating the provider.
* @param options Configuration options required to initialize the authentication provider.
*
* @returns An instance of an AuthProvider initialized with the given options.
*
* @throws {StrapiSDKError} Throws an error if the specified strategy is not registered in the factory.
*
* @example
* ```typescript
* const factory = new AuthProviderFactory();
*
* factory.register(
* 'api-token',
* (options: ApiTokenAuthProviderOptions) => new ApiTokenAuthProvider(options)
* );
*
* const provider = factory.create('api-token', { jwt: 'token' });
* ```
*/
create<T_Strategy extends StringKeysOf<T_Providers> | string>(
authStrategy: T_Strategy,
options: CreateAuthProviderParams<T_Providers, T_Strategy>
): AuthProvider {
const creator = this._registry.get(authStrategy);

if (!creator) {
throw new StrapiSDKError(`Auth strategy "${authStrategy}" is not supported.`);
}

return creator(options);
}

/**
* Registers a new authentication strategy with the factory.
*
* @param strategy The name of the authentication strategy to register.
* @param creator A function that creates an instance of an authentication provider for the specified strategy.
*
* @returns The instance of AuthProviderFactory, for chaining purpose.
*
* @example
* ```typescript
* const factory = new AuthProviderFactory();
*
* factory
* .register(
* 'api-token',
* (options: ApiTokenAuthProviderOptions) => new ApiTokenAuthProvider(options)
* )
* .register(
* 'users-permissions',
* (options: UsersPermissionsAuthProviderOptions) => new UsersPermissionsAuthProvider(options)
* );
* ```
*/
register<T_Strategy extends string, T_Creator extends AuthProviderCreator>(
strategy: T_Strategy,
creator: T_Creator
) {
this._registry.set(strategy, creator);

return this as AuthProviderFactory<T_Providers & { [key in T_Strategy]: typeof creator }>;
}
}
1 change: 1 addition & 0 deletions src/auth/factory/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './factory';
10 changes: 10 additions & 0 deletions src/auth/factory/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { AuthProvider } from '../providers';

export type AuthProviderCreator<T = any> = (options: T) => AuthProvider;

export type AuthProviderMap = { [key: string]: AuthProviderCreator };

export type CreateAuthProviderParams<
T_Providers extends AuthProviderMap,
T_Strategy extends StringKeysOf<T_Providers>,
> = T_Providers[T_Strategy] extends AuthProviderCreator<infer T_Options> ? T_Options : unknown;
4 changes: 4 additions & 0 deletions src/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './providers';
export * from './factory';

export * from './manager';
Loading
Loading