From ca377b119f20239c7977ffa6ffe9a9910921bd0a Mon Sep 17 00:00:00 2001 From: Convly Date: Tue, 28 Jan 2025 11:10:08 +0100 Subject: [PATCH 01/11] fix(interceptors): prevent overriding existing headers --- src/interceptors/http.ts | 10 +++++++++- tests/unit/interceptors/http.test.ts | 4 ++-- tests/unit/sdk.test.ts | 28 ++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/interceptors/http.ts b/src/interceptors/http.ts index 10fe8a7..c088dc2 100644 --- a/src/interceptors/http.ts +++ b/src/interceptors/http.ts @@ -26,8 +26,16 @@ export class HttpInterceptors { *``` */ public static setDefaultHeaders(): RequestInterceptor { + const DEFAULT_HEADERS = new Map([['Content-Type', 'application/json']]); + return ({ request }) => { - request.headers.set('Content-Type', 'application/json'); + for (const [key, value] of DEFAULT_HEADERS.entries()) { + const hasHeader = request.headers.has(key); + + if (!hasHeader) { + request.headers.set(key, value); + } + } return { request }; }; diff --git a/tests/unit/interceptors/http.test.ts b/tests/unit/interceptors/http.test.ts index 384cbc5..267b7d6 100644 --- a/tests/unit/interceptors/http.test.ts +++ b/tests/unit/interceptors/http.test.ts @@ -16,7 +16,7 @@ describe('HTTP Interceptors', () => { expect(request.headers.get('Content-Type')).toBe('application/json'); }); - it('should override the headers in the given request', async () => { + it('should not override the headers if a value is already set', async () => { // Arrange const request = new Request('https://example.com', { headers: { 'Content-Type': 'text/plain' }, @@ -28,7 +28,7 @@ describe('HTTP Interceptors', () => { await interceptor({ request }); // Assert - expect(request.headers.get('Content-Type')).toBe('application/json'); + expect(request.headers.get('Content-Type')).toBe('text/plain'); }); }); diff --git a/tests/unit/sdk.test.ts b/tests/unit/sdk.test.ts index 10d7533..f300e35 100644 --- a/tests/unit/sdk.test.ts +++ b/tests/unit/sdk.test.ts @@ -192,6 +192,34 @@ describe('Strapi', () => { expect((headers as Headers).get('Content-Type')).toBe('application/json'); }); + it('should not set the application/json Content-Type header if it has been manually set', async () => { + // Arrange + const path = '/upload'; + const contentType = 'multipart/form-data'; + + const config = { baseURL: 'https://localhost:1337/api' } satisfies StrapiConfig; + const init = { + method: 'POST', + headers: { 'Content-Type': contentType }, + } satisfies RequestInit; + + const mockValidator = new MockStrapiConfigValidator(); + const mockAuthManager = new MockAuthManager(); + + const sdk = new Strapi(config, mockValidator, mockAuthManager, mockHttpClientFactory); + + const fetchSpy = jest.spyOn(MockHttpClient.prototype, 'fetch'); + + // Act + await sdk.fetch(path, init); + const headers = fetchSpy.mock.lastCall?.[1]?.headers; + + // Assert + expect(headers).toBeDefined(); + expect(headers).toBeInstanceOf(Headers); + expect((headers as Headers).get('Content-Type')).toBe(contentType); + }); + it.each([ ['Bad Request', StatusCode.BAD_REQUEST, HTTPBadRequestError], ['Unauthorized', StatusCode.UNAUTHORIZED, HTTPAuthorizationError], From a2c1b77c7c07df4d3a223ca5efeed84087da7b01 Mon Sep 17 00:00:00 2001 From: Convly Date: Tue, 28 Jan 2025 11:35:58 +0100 Subject: [PATCH 02/11] test(http-interceptors): add case insensitive header check --- tests/unit/interceptors/http.test.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/unit/interceptors/http.test.ts b/tests/unit/interceptors/http.test.ts index 267b7d6..671b2fb 100644 --- a/tests/unit/interceptors/http.test.ts +++ b/tests/unit/interceptors/http.test.ts @@ -30,6 +30,21 @@ describe('HTTP Interceptors', () => { // Assert expect(request.headers.get('Content-Type')).toBe('text/plain'); }); + + it('should perform case insensitive checks on headers', async () => { + // Arrange + const request = new Request('https://example.com', { + headers: { 'content-type': 'text/plain' }, + }); + + const interceptor = HttpInterceptors.setDefaultHeaders(); + + // Act + await interceptor({ request }); + + // Assert + expect(request.headers.get('Content-Type')).toBe('text/plain'); + }); }); describe('transformErrors', () => { From 408cd61d3bc9a95dc3147a7b3bec6f02b9ab3b9c Mon Sep 17 00:00:00 2001 From: Convly Date: Wed, 29 Jan 2025 15:54:02 +0100 Subject: [PATCH 03/11] feat(sdk): simplify auth config with direct token support --- README.md | 8 ++--- src/index.ts | 68 +++++++++++++++++++++++++++++++--------- src/sdk.ts | 19 ++++++----- tests/unit/index.test.ts | 36 ++++++++++++++------- tests/unit/sdk.test.ts | 37 ++++++++++++++++++++-- 5 files changed, 129 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index f00f83f..5698986 100644 --- a/README.md +++ b/README.md @@ -108,11 +108,10 @@ If your Strapi instance uses API tokens, configure the SDK like this: ```typescript const sdk = strapi({ + // Endpoint configuration baseURL: 'http://localhost:1337/api', - auth: { - strategy: 'api-token', - options: { token: 'your-api-token-here' }, - }, + // Auth configuration + auth: 'your-api-token-here', }); ``` @@ -248,7 +247,6 @@ Below is a list of available namespaces to use: | `strapi:auth:factory` | Logs the registration and creation of authentication providers. | | `strapi:auth:manager` | Logs authentication lifecycle management. | | `strapi:auth:provider:api-token` | Logs operations related to API token authentication. | -| `strapi:auth:provider:users-permissions` | Logs operations related to user and permissions-based authentication. | | `strapi:ct:collection` | Logs interactions with collection-type content managers. | | `strapi:ct:single` | Logs interactions with single-type content managers. | | `strapi:utils:url-helper` | Logs URL helper utility operations (e.g., appending query parameters or formatting URLs). | diff --git a/src/index.ts b/src/index.ts index cbdff78..b60a5c2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,46 @@ +import { ApiTokenAuthProvider } from './auth'; import { Strapi } from './sdk'; -import { StrapiConfigValidator } from './validators'; import type { StrapiConfig } from './sdk'; export * from './errors'; +export interface Config { + /** + * The base URL of the Strapi content API. + * + * This specifies where the SDK should send requests. + * + * The URL must include the protocol (`http` or `https`) and serve + * as the root path for all later API operations. + * + * @example + * 'https://api.example.com' + * + * @remarks + * Failing to provide a valid HTTP or HTTPS URL results in a + * `StrapiInitializationError`. + */ + baseURL: string; + + /** + * API token to authenticate requests (optional). + * + * When provided, this token is included in the `Authorization` header + * of every request to the Strapi API. + * + * @remarks + * - A valid token must be a non-empty string. + * + * - If the token is invalid or improperly formatted, the SDK + * throws a `StrapiValidationError` during initialization. + * + * - If excluded, the SDK operates without authentication. + */ + + auth?: string; +} + /** * Creates a new instance of the Strapi SDK with a specified configuration. * @@ -25,10 +61,7 @@ export * from './errors'; * // Basic configuration using API token auth * const config = { * baseURL: 'https://api.example.com', - * auth: { - * strategy: 'api-token', - * options: { token: 'your_token_here' } - * } + * auth: 'your_token_here', * }; * * // Create the SDK instance @@ -44,13 +77,20 @@ export * from './errors'; * @throws {StrapiInitializationError} If the provided baseURL doesn't conform to a valid HTTP or HTTPS URL, * or if the auth configuration is invalid. */ -export const strapi = (config: StrapiConfig) => { - const configValidator = new StrapiConfigValidator(); - - return new Strapi( - // Properties - config, - // Dependencies - configValidator - ); +export const strapi = (config: Config) => { + const { baseURL, auth } = config; + + const sdkConfig: StrapiConfig = { baseURL }; + + // In this factory, to keep things simple, users can't manually set the strategy options. + // Since the SDK constructor needs to define a proper strategy, + // it is handled here if the auth property is provided + if (auth !== undefined) { + sdkConfig.auth = { + strategy: ApiTokenAuthProvider.identifier, + options: { token: auth }, + }; + } + + return new Strapi(sdkConfig); }; diff --git a/src/sdk.ts b/src/sdk.ts index 68ea7d7..1c00d47 100644 --- a/src/sdk.ts +++ b/src/sdk.ts @@ -2,7 +2,7 @@ import createDebug from 'debug'; import { AuthManager } from './auth'; import { CollectionTypeManager, SingleTypeManager } from './content-types'; -import { StrapiInitializationError } from './errors'; +import { StrapiError, StrapiInitializationError } from './errors'; import { HttpClient } from './http'; import { AuthInterceptors, HttpInterceptors } from './interceptors'; import { StrapiConfigValidator } from './validators'; @@ -39,12 +39,10 @@ export interface AuthConfig { * * It serves as the main interface through which users interact with * their Strapi installation programmatically. - * - * @template T_Config - Configuration type inferred from the user-provided SDK configuration */ -export class Strapi { +export class Strapi { /** @internal */ - private readonly _config: T_Config; + private readonly _config: StrapiConfig; /** @internal */ private readonly _validator: StrapiConfigValidator; @@ -58,7 +56,7 @@ export class Strapi { /** @internal */ constructor( // Properties - config: T_Config, + config: StrapiConfig, // Dependencies validator: StrapiConfigValidator = new StrapiConfigValidator(), @@ -189,7 +187,14 @@ export class Strapi { debug('setting up the auth strategy using %o', strategy); - this._authManager.setStrategy(strategy, options); + try { + this._authManager.setStrategy(strategy, options); + } catch (e) { + throw new StrapiInitializationError( + e, + `Failed to initialize the SDK auth manager: ${e instanceof StrapiError ? e.cause : e}` + ); + } } this._httpClient.interceptors.request diff --git a/tests/unit/index.test.ts b/tests/unit/index.test.ts index 8079848..0103e84 100644 --- a/tests/unit/index.test.ts +++ b/tests/unit/index.test.ts @@ -1,12 +1,13 @@ -import { strapi, StrapiInitializationError, StrapiValidationError } from '../../src'; +import { strapi, StrapiInitializationError } from '../../src'; +import { ApiTokenAuthProvider } from '../../src/auth'; import { Strapi } from '../../src/sdk'; -import type { StrapiConfig } from '../../src/sdk'; +import type { Config } from '../../src'; describe('strapi', () => { - it('should create an SDK instance with valid configuration', () => { + it('should create an SDK instance with valid http configuration', () => { // Arrange - const config = { baseURL: 'https://api.example.com' } satisfies StrapiConfig; + const config = { baseURL: 'https://api.example.com' } satisfies Config; // Act const sdk = strapi(config); @@ -16,9 +17,25 @@ describe('strapi', () => { expect(sdk).toHaveProperty('baseURL', config.baseURL); }); + it('should create an SDK instance with valid auth configuration', () => { + // Arrange + const token = ''; + const config = { baseURL: 'https://api.example.com', auth: token } satisfies Config; + + // Act + const sdk = strapi(config); + + // Assert + expect(sdk).toBeInstanceOf(Strapi); + expect(sdk).toHaveProperty('auth', { + strategy: ApiTokenAuthProvider.identifier, // default auth strategy + options: { token }, + }); + }); + it('should throw an error for an invalid baseURL', () => { // Arrange - const config = { baseURL: 'invalid-url' } satisfies StrapiConfig; + const config = { baseURL: 'invalid-url' } satisfies Config; // Act & Assert expect(() => strapi(config)).toThrow(StrapiInitializationError); @@ -28,13 +45,10 @@ describe('strapi', () => { // Arrange const config = { baseURL: 'https://api.example.com', - auth: { - strategy: 'api-token', - options: { token: '' }, // Invalid token - }, - } satisfies StrapiConfig; + auth: '', // Invalid API token + } satisfies Config; // Act & Assert - expect(() => strapi(config)).toThrow(StrapiValidationError); + expect(() => strapi(config)).toThrow(StrapiInitializationError); }); }); diff --git a/tests/unit/sdk.test.ts b/tests/unit/sdk.test.ts index 10d7533..5968e14 100644 --- a/tests/unit/sdk.test.ts +++ b/tests/unit/sdk.test.ts @@ -6,7 +6,9 @@ import { HTTPInternalServerError, HTTPNotFoundError, HTTPTimeoutError, + StrapiError, StrapiInitializationError, + StrapiValidationError, } from '../../src'; import { CollectionTypeManager, SingleTypeManager } from '../../src/content-types'; import { HttpClient, StatusCode } from '../../src/http'; @@ -46,7 +48,7 @@ describe('Strapi', () => { // Arrange const config = { baseURL: 'https://localhost:1337/api', - auth: { strategy: MockAuthProvider.identifier, options: {} }, + auth: { strategy: MockAuthProvider.identifier }, } satisfies StrapiConfig; const mockValidator = new MockStrapiConfigValidator(); @@ -62,7 +64,7 @@ describe('Strapi', () => { expect(sdk).toBeInstanceOf(Strapi); expect(validatorSpy).toHaveBeenCalledWith(config); - expect(authSetStrategySpy).toHaveBeenCalledWith(MockAuthProvider.identifier, {}); + expect(authSetStrategySpy).toHaveBeenCalledWith(MockAuthProvider.identifier, undefined); }); it('should not set the auth strategy if no auth config is provided', () => { @@ -82,6 +84,37 @@ describe('Strapi', () => { expect(authSetStrategySpy).not.toHaveBeenCalled(); }); + it.each([ + ['common error', new Error('unexpected error')], + ['strapi error', new StrapiError(new StrapiValidationError('invalid auth configuration'))], + ])( + 'should throw an initialization error if a %s error occurs during the auth strategy init', + async (_title, error) => { + // Arrange + const config = { + baseURL: 'https://localhost:1337/api', + auth: { strategy: MockAuthProvider.identifier }, + } satisfies StrapiConfig; + + const mockValidator = new MockStrapiConfigValidator(); + const mockAuthManager = new MockAuthManager(); + + jest.spyOn(mockAuthManager, 'setStrategy').mockImplementationOnce(() => { + throw error; + }); + + // Act + expect( + () => new Strapi(config, mockValidator, mockAuthManager, mockHttpClientFactory) + ).toThrow(StrapiInitializationError); + + expect(mockAuthManager.setStrategy).toHaveBeenCalledWith( + MockAuthProvider.identifier, + undefined + ); + } + ); + it('should throw an error on invalid baseURL', () => { // Arrange const config = { baseURL: 'invalid-url' } satisfies StrapiConfig; From 8fbcbbf75ff8b414b65b5497a4a9044f37abc80d Mon Sep 17 00:00:00 2001 From: Convly Date: Wed, 29 Jan 2025 15:54:39 +0100 Subject: [PATCH 04/11] chore(README): fix table formatting for namespaces list --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 5698986..f7f1cff 100644 --- a/README.md +++ b/README.md @@ -238,15 +238,15 @@ The `debug` tool allows you to control logs using wildcard patterns (`*`): Below is a list of available namespaces to use: -| Namespace | Description | -| ---------------------------------------- | ----------------------------------------------------------------------------------------- | -| `strapi:core` | Logs SDK initialization, configuration validation, and HTTP client setup. | -| `strapi:validators:config` | Logs details related to SDK configuration validation. | -| `strapi:validators:url` | Logs URL validation processes. | -| `strapi:http` | Logs HTTP client setup, request processing, and response/error handling. | -| `strapi:auth:factory` | Logs the registration and creation of authentication providers. | -| `strapi:auth:manager` | Logs authentication lifecycle management. | -| `strapi:auth:provider:api-token` | Logs operations related to API token authentication. | -| `strapi:ct:collection` | Logs interactions with collection-type content managers. | -| `strapi:ct:single` | Logs interactions with single-type content managers. | -| `strapi:utils:url-helper` | Logs URL helper utility operations (e.g., appending query parameters or formatting URLs). | +| Namespace | Description | +| -------------------------------- | ----------------------------------------------------------------------------------------- | +| `strapi:core` | Logs SDK initialization, configuration validation, and HTTP client setup. | +| `strapi:validators:config` | Logs details related to SDK configuration validation. | +| `strapi:validators:url` | Logs URL validation processes. | +| `strapi:http` | Logs HTTP client setup, request processing, and response/error handling. | +| `strapi:auth:factory` | Logs the registration and creation of authentication providers. | +| `strapi:auth:manager` | Logs authentication lifecycle management. | +| `strapi:auth:provider:api-token` | Logs operations related to API token authentication. | +| `strapi:ct:collection` | Logs interactions with collection-type content managers. | +| `strapi:ct:single` | Logs interactions with single-type content managers. | +| `strapi:utils:url-helper` | Logs URL helper utility operations (e.g., appending query parameters or formatting URLs). | From 8232877b8cd9940b72c2082afb7e6cd93d86cd26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Herbaux?= Date: Wed, 29 Jan 2025 16:03:40 +0100 Subject: [PATCH 05/11] chore: update wording in src/index.ts Co-authored-by: Ben Irvin --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index b60a5c2..a31ca81 100644 --- a/src/index.ts +++ b/src/index.ts @@ -82,7 +82,7 @@ export const strapi = (config: Config) => { const sdkConfig: StrapiConfig = { baseURL }; - // In this factory, to keep things simple, users can't manually set the strategy options. + // In this factory, while there is only one auth strategy available, users can't manually set the strategy options. // Since the SDK constructor needs to define a proper strategy, // it is handled here if the auth property is provided if (auth !== undefined) { From 074fc181ea96cc631e35441b5c31ecf4081640f8 Mon Sep 17 00:00:00 2001 From: Convly Date: Thu, 30 Jan 2025 11:42:18 +0100 Subject: [PATCH 06/11] chore(config): remove useless indentation rules --- .editorconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.editorconfig b/.editorconfig index 473e451..4a7ea30 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,9 +8,5 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -[{package.json,*.yml}] -indent_style = space -indent_size = 2 - [*.md] trim_trailing_whitespace = false From 0b235904a830ac0618f43840b760be816bcca361 Mon Sep 17 00:00:00 2001 From: Convly Date: Thu, 30 Jan 2025 11:50:09 +0100 Subject: [PATCH 07/11] chore(demos): add Node.js JavaScript demo --- demos/demo-node-javascript/index.js | 16 ++++++++++++++++ demos/demo-node-javascript/package.json | 20 ++++++++++++++++++++ demos/demo-node-javascript/pnpm-lock.yaml | 12 ++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 demos/demo-node-javascript/index.js create mode 100644 demos/demo-node-javascript/package.json create mode 100644 demos/demo-node-javascript/pnpm-lock.yaml diff --git a/demos/demo-node-javascript/index.js b/demos/demo-node-javascript/index.js new file mode 100644 index 0000000..6dccc51 --- /dev/null +++ b/demos/demo-node-javascript/index.js @@ -0,0 +1,16 @@ +const { strapi } = require('@strapi/sdk-js'); + +async function main() { + // Create the SDK instance + const sdk = strapi({ baseURL: 'http://localhost:1337/api' }); + + // Create a collection type query manager for the categories + const categories = sdk.collection('categories'); + + // Fetch the list of all categories + const docs = await categories.find(); + + console.dir(docs, { depth: null }); +} + +main().catch(console.error); diff --git a/demos/demo-node-javascript/package.json b/demos/demo-node-javascript/package.json new file mode 100644 index 0000000..da443e1 --- /dev/null +++ b/demos/demo-node-javascript/package.json @@ -0,0 +1,20 @@ +{ + "name": "demo-node-javascript", + "version": "1.0.0", + "description": "A Strapi SDK demo using a Node x JavaScript application", + "main": "index.js", + "scripts": { + "start": "node index.js", + "debug": "DEBUG=* node index.js" + }, + "dependencies": { + "@strapi/sdk-js": "link:../.." + }, + "keywords": [], + "author": { + "name": "Strapi Solutions SAS", + "email": "hi@strapi.io", + "url": "https://strapi.io" + }, + "license": "ISC" +} diff --git a/demos/demo-node-javascript/pnpm-lock.yaml b/demos/demo-node-javascript/pnpm-lock.yaml new file mode 100644 index 0000000..08fcad6 --- /dev/null +++ b/demos/demo-node-javascript/pnpm-lock.yaml @@ -0,0 +1,12 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + '@strapi/sdk-js': + specifier: link:../.. + version: link:../.. From 6d5235bc41e50d45d6a076094b95bfae3c52abb6 Mon Sep 17 00:00:00 2001 From: Convly Date: Thu, 30 Jan 2025 13:08:12 +0100 Subject: [PATCH 08/11] chore(build): update output file extensions for bundler --- package.json | 4 ++-- rollup.config.mjs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 6539c5a..a4db287 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,8 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "require": "./dist/bundle.cjs.js", - "import": "./dist/bundle.esm.js", + "require": "./dist/bundle.cjs", + "import": "./dist/bundle.mjs", "browser": { "import": "./dist/bundle.browser.min.js", "require": "./dist/bundle.browser.min.js" diff --git a/rollup.config.mjs b/rollup.config.mjs index a058b89..4f51b6e 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -35,14 +35,14 @@ const node_build = { output: [ // CommonJS build { - file: 'dist/bundle.cjs.js', + file: 'dist/bundle.cjs', format: 'cjs', sourcemap: isProduction ? 'hidden' : true, exports: 'named', }, // ESM build { - file: 'dist/bundle.esm.js', + file: 'dist/bundle.mjs', format: 'esm', sourcemap: isProduction ? 'hidden' : true, exports: 'named', From 7815260f7cf070a00e2bf90b278dbd61d1db9c73 Mon Sep 17 00:00:00 2001 From: Convly Date: Thu, 30 Jan 2025 13:08:49 +0100 Subject: [PATCH 09/11] chore(build): update output file extensions in doc --- rollup.config.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rollup.config.mjs b/rollup.config.mjs index 4f51b6e..1556636 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -13,11 +13,11 @@ const isProduction = process.env.NODE_ENV === 'production'; * system, ensuring compatibility with a wide range of tools and runtimes. * * Outputs: - * - CommonJS (dist/bundle.cjs.js): for environments using `require`. + * - CommonJS (dist/bundle.cjs): for environments using `require`. * Compatible with older tools and Node.js versions. * Includes source maps for debugging. * - * - ES Module (dist/bundle.esm.js): for modern import/export environments. + * - ES Module (dist/bundle.esm): for modern import/export environments. * Supports tree-shaking for smaller builds and also includes source maps. * * Plugins Used: From fdf9fd30af995a3529664f6398156e33bfe9f045 Mon Sep 17 00:00:00 2001 From: Convly Date: Thu, 30 Jan 2025 13:11:13 +0100 Subject: [PATCH 10/11] chore(demos): add demo for node and TypeScript using Strapi SDK --- demos/demo-node-typescript/package.json | 27 ++++++++++++++++++++++ demos/demo-node-typescript/pnpm-lock.yaml | 28 +++++++++++++++++++++++ demos/demo-node-typescript/src/index.ts | 12 ++++++++++ demos/demo-node-typescript/tsconfig.json | 26 +++++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 demos/demo-node-typescript/package.json create mode 100644 demos/demo-node-typescript/pnpm-lock.yaml create mode 100644 demos/demo-node-typescript/src/index.ts create mode 100644 demos/demo-node-typescript/tsconfig.json diff --git a/demos/demo-node-typescript/package.json b/demos/demo-node-typescript/package.json new file mode 100644 index 0000000..bab7024 --- /dev/null +++ b/demos/demo-node-typescript/package.json @@ -0,0 +1,27 @@ +{ + "name": "demo-node-typescript", + "version": "1.0.0", + "description": "A Strapi SDK demo using a Node x TypeScript application", + "main": "dist/index.js", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -p tsconfig.json", + "watch": "tsc -p tsconfig.json -w", + "start": "node dist/index.js", + "debug": "DEBUG=* node dist/index.js" + }, + "dependencies": { + "@strapi/sdk-js": "link:../.." + }, + "devDependencies": { + "typescript": "5.7.3" + }, + "keywords": [], + "author": { + "name": "Strapi Solutions SAS", + "email": "hi@strapi.io", + "url": "https://strapi.io" + }, + "license": "ISC" +} diff --git a/demos/demo-node-typescript/pnpm-lock.yaml b/demos/demo-node-typescript/pnpm-lock.yaml new file mode 100644 index 0000000..868fce2 --- /dev/null +++ b/demos/demo-node-typescript/pnpm-lock.yaml @@ -0,0 +1,28 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: + dependencies: + '@strapi/sdk-js': + specifier: link:../.. + version: link:../.. + devDependencies: + typescript: + specifier: 5.7.3 + version: 5.7.3 + +packages: + typescript@5.7.3: + resolution: + { + integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==, + } + engines: { node: '>=14.17' } + hasBin: true + +snapshots: + typescript@5.7.3: {} diff --git a/demos/demo-node-typescript/src/index.ts b/demos/demo-node-typescript/src/index.ts new file mode 100644 index 0000000..b803d47 --- /dev/null +++ b/demos/demo-node-typescript/src/index.ts @@ -0,0 +1,12 @@ +import { strapi } from '@strapi/sdk-js'; + +// Create the SDK instance +const sdk = strapi({ baseURL: 'http://localhost:1337/api' }); + +// Create a collection type query manager for the categories +const categories = sdk.collection('categories'); + +// Fetch the list of all categories +const docs = await categories.find(); + +console.dir(docs, { depth: null }); diff --git a/demos/demo-node-typescript/tsconfig.json b/demos/demo-node-typescript/tsconfig.json new file mode 100644 index 0000000..a1c54f0 --- /dev/null +++ b/demos/demo-node-typescript/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + /* Language and Environment */ + "allowSyntheticDefaultImports": true, + + /* Modules */ + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "module": "NodeNext", + + /* Emit */ + "moduleResolution": "NodeNext", + + /* Interop Constraints */ + + "outDir": "./dist", + "rootDir": "./src", + "skipLibCheck": false, + + /* Type Checking */ + "strict": true, + + /* Completeness */ + "target": "ESNext" + } +} From 0a7eac3a41290dda1c11cc2756a5797ddf4e1b7f Mon Sep 17 00:00:00 2001 From: Convly Date: Thu, 30 Jan 2025 13:12:29 +0100 Subject: [PATCH 11/11] chore(demo): rename demos/ to demo/ --- {demos => demo}/demo-node-javascript/index.js | 0 {demos => demo}/demo-node-javascript/package.json | 0 {demos => demo}/demo-node-javascript/pnpm-lock.yaml | 0 {demos => demo}/demo-node-typescript/package.json | 0 {demos => demo}/demo-node-typescript/pnpm-lock.yaml | 0 {demos => demo}/demo-node-typescript/src/index.ts | 0 {demos => demo}/demo-node-typescript/tsconfig.json | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {demos => demo}/demo-node-javascript/index.js (100%) rename {demos => demo}/demo-node-javascript/package.json (100%) rename {demos => demo}/demo-node-javascript/pnpm-lock.yaml (100%) rename {demos => demo}/demo-node-typescript/package.json (100%) rename {demos => demo}/demo-node-typescript/pnpm-lock.yaml (100%) rename {demos => demo}/demo-node-typescript/src/index.ts (100%) rename {demos => demo}/demo-node-typescript/tsconfig.json (100%) diff --git a/demos/demo-node-javascript/index.js b/demo/demo-node-javascript/index.js similarity index 100% rename from demos/demo-node-javascript/index.js rename to demo/demo-node-javascript/index.js diff --git a/demos/demo-node-javascript/package.json b/demo/demo-node-javascript/package.json similarity index 100% rename from demos/demo-node-javascript/package.json rename to demo/demo-node-javascript/package.json diff --git a/demos/demo-node-javascript/pnpm-lock.yaml b/demo/demo-node-javascript/pnpm-lock.yaml similarity index 100% rename from demos/demo-node-javascript/pnpm-lock.yaml rename to demo/demo-node-javascript/pnpm-lock.yaml diff --git a/demos/demo-node-typescript/package.json b/demo/demo-node-typescript/package.json similarity index 100% rename from demos/demo-node-typescript/package.json rename to demo/demo-node-typescript/package.json diff --git a/demos/demo-node-typescript/pnpm-lock.yaml b/demo/demo-node-typescript/pnpm-lock.yaml similarity index 100% rename from demos/demo-node-typescript/pnpm-lock.yaml rename to demo/demo-node-typescript/pnpm-lock.yaml diff --git a/demos/demo-node-typescript/src/index.ts b/demo/demo-node-typescript/src/index.ts similarity index 100% rename from demos/demo-node-typescript/src/index.ts rename to demo/demo-node-typescript/src/index.ts diff --git a/demos/demo-node-typescript/tsconfig.json b/demo/demo-node-typescript/tsconfig.json similarity index 100% rename from demos/demo-node-typescript/tsconfig.json rename to demo/demo-node-typescript/tsconfig.json