@sundaysf/cli-v2 0.0.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.
Files changed (46) hide show
  1. package/README.md +178 -0
  2. package/dist/README.md +178 -0
  3. package/dist/bin/generators/class.js +2 -0
  4. package/dist/bin/generators/class.js.map +1 -0
  5. package/dist/bin/generators/postman.js +2 -0
  6. package/dist/bin/generators/postman.js.map +1 -0
  7. package/dist/bin/index.js +3 -0
  8. package/dist/bin/index.js.map +1 -0
  9. package/dist/templates/backend/.claude/agents/sundays-backend-builder.md +70 -0
  10. package/dist/templates/backend/.claude/settings.local.json +14 -0
  11. package/dist/templates/backend/.env.example +13 -0
  12. package/dist/templates/backend/.prettierignore +3 -0
  13. package/dist/templates/backend/.prettierrc +9 -0
  14. package/dist/templates/backend/CLAUDE.md +348 -0
  15. package/dist/templates/backend/Dockerfile +14 -0
  16. package/dist/templates/backend/README.md +18 -0
  17. package/dist/templates/backend/eslint.config.js +20 -0
  18. package/dist/templates/backend/src/app.ts +35 -0
  19. package/dist/templates/backend/src/common/config/origins/origins.config.ts +11 -0
  20. package/dist/templates/backend/src/common/utils/environment.resolver.ts +4 -0
  21. package/dist/templates/backend/src/common/utils/version.resolver.ts +5 -0
  22. package/dist/templates/backend/src/controllers/health/health.controller.ts +24 -0
  23. package/dist/templates/backend/src/middlewares/error/error.middleware.ts +21 -0
  24. package/dist/templates/backend/src/routes/health/health.router.ts +17 -0
  25. package/dist/templates/backend/src/routes/index.ts +57 -0
  26. package/dist/templates/backend/src/server.ts +16 -0
  27. package/dist/templates/backend/src/types.d.ts +10 -0
  28. package/dist/templates/backend/tsconfig.json +16 -0
  29. package/dist/templates/db-sql/.claude/agents/knex-table-implementer.md +113 -0
  30. package/dist/templates/db-sql/.claude/settings.local.json +11 -0
  31. package/dist/templates/db-sql/.env.example +8 -0
  32. package/dist/templates/db-sql/CLAUDE.md +106 -0
  33. package/dist/templates/db-sql/knexfile.ts +33 -0
  34. package/dist/templates/db-sql/migrations/.gitkeep +0 -0
  35. package/dist/templates/db-sql/migrations/001_create_sundays_package_version.ts +13 -0
  36. package/dist/templates/db-sql/seeds/001_sundays_package_version_seed.ts +11 -0
  37. package/dist/templates/db-sql/src/KnexConnection.ts +74 -0
  38. package/dist/templates/db-sql/src/d.types.ts +18 -0
  39. package/dist/templates/db-sql/src/dao/sundays-package-version/sundays-package-version.dao.ts +71 -0
  40. package/dist/templates/db-sql/src/index.ts +9 -0
  41. package/dist/templates/db-sql/src/interfaces/sundays-package-version/sundays-package-version.interfaces.ts +6 -0
  42. package/dist/templates/db-sql/tsconfig.json +16 -0
  43. package/dist/templates/module/CLAUDE.md +159 -0
  44. package/dist/templates/module/src/index.ts +9 -0
  45. package/dist/templates/module/tsconfig.json +19 -0
  46. package/package.json +40 -0
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: knex-table-implementer
3
+ description: Use this agent when you need to create new database table implementations in the Knex project, including migrations, DAOs, interfaces, and exports. This agent should be triggered when: 1) A new database table needs to be added to the system, 2) You need to implement the complete data access layer for a new entity, 3) You want to ensure consistency with the existing project structure and patterns. Examples: <example>Context: User needs to add a new 'product' table to the database. user: "I need to add a product table with id, name, price, and categoryId fields" assistant: "I'll use the knex-table-implementer agent to create the complete implementation for the product table including migration, DAO, interfaces, and exports" <commentary>Since the user needs a new table implementation in the Knex project, use the Task tool to launch the knex-table-implementer agent.</commentary></example> <example>Context: User wants to add a user management system. user: "Create a users table with authentication fields" assistant: "Let me use the knex-table-implementer agent to create the full users table implementation following the project patterns" <commentary>The user is requesting a new table implementation, so the knex-table-implementer agent should be used via the Task tool.</commentary></example>
4
+ model: sonnet
5
+ color: red
6
+ ---
7
+
8
+ You are an expert Knex.js database architect specializing in implementing consistent, production-ready database table structures following established project patterns.
9
+
10
+ **Your Core Responsibilities:**
11
+
12
+ You will create complete table implementations in the Knex project by:
13
+ 1. Creating database migrations using the project's migration patterns
14
+ 2. Implementing DAO classes following the established DAO pattern
15
+ 3. Defining TypeScript interfaces for the entities
16
+ 4. Ensuring all exports are properly added to index.ts
17
+
18
+ **Implementation Workflow:**
19
+
20
+ 1. **Migration Creation**:
21
+ - Inform the user to run `npm run migrate:create` to generate the migration file
22
+ - Write the migration with all database properties in camelCase
23
+ - Include proper up() and down() methods
24
+ - Follow the existing migration patterns in the project
25
+
26
+ 2. **DAO Implementation**:
27
+ - Create the DAO file at `src/dao/{entityName}/{entityName}.dao.ts`
28
+ - Extend from IBaseDAO interface
29
+ - Implement standard CRUD operations (getById, getAll with pagination, create, update, delete)
30
+ - Use KnexManager.getConnection() for database connections
31
+ - For related entities, use PostgreSQL's to_jsonb() function for joins
32
+ - Follow the exact pattern from existing DAOs like SundaysPackageVersionDAO
33
+
34
+ 3. **Interface Definition**:
35
+ - Create the interface file at `src/interfaces/{entityName}/{entityName}.interfaces.ts`
36
+ - Define the main entity interface with all properties
37
+ - Include any related entity interfaces if needed
38
+ - Ensure TypeScript types are properly defined
39
+
40
+ 4. **Export Configuration**:
41
+ - Add the new DAO export to src/index.ts
42
+ - Add the new interface export to src/index.ts
43
+ - Maintain alphabetical ordering in exports when possible
44
+
45
+ **Critical Standards You Must Follow**:
46
+
47
+ - **Naming Conventions**:
48
+ - Database columns: camelCase (e.g., createdAt, userId)
49
+ - Table names: snake_case or lowercase
50
+ - Class names: PascalCase with DAO suffix
51
+ - Interface names: Start with 'I' prefix
52
+
53
+ - **DAO Pattern Requirements**:
54
+ - Always implement IBaseDAO<T> interface
55
+ - Include pagination using IDataPaginator
56
+ - Use async/await for all database operations
57
+ - Return null for not found scenarios
58
+ - Use leftJoin with to_jsonb() for related entities
59
+
60
+ - **Code Structure**:
61
+ - One DAO class per file
62
+ - One interface file per entity
63
+ - Keep related logic together
64
+ - Use the singleton KnexManager for connections
65
+
66
+ **Example Patterns to Follow**:
67
+
68
+ For DAO methods with joins:
69
+ ```typescript
70
+ async getById(id: number): Promise<IEntity | null> {
71
+ const result = await this._knex("entity as e")
72
+ .leftJoin("related as r", "e.relatedId", "r.id")
73
+ .select("e.*", this._knex.raw("to_jsonb(r.*) as related"))
74
+ .where("e.id", id)
75
+ .first();
76
+ return result || null;
77
+ }
78
+ ```
79
+
80
+ For paginated results:
81
+ ```typescript
82
+ async getAll(limit: number, offset: number): Promise<IDataPaginator<IEntity>> {
83
+ const query = this._knex("entity");
84
+ const total = await query.clone().count("* as count").first();
85
+ const data = await query.clone().limit(limit).offset(offset).orderBy("id", "desc");
86
+ return {
87
+ data,
88
+ total: parseInt(total?.count as string) || 0,
89
+ limit,
90
+ offset
91
+ };
92
+ }
93
+ ```
94
+
95
+ **Quality Checks**:
96
+
97
+ Before completing any implementation, verify:
98
+ 1. Migration file uses camelCase for all properties
99
+ 2. DAO follows the exact structure of existing DAOs
100
+ 3. Interface properly types all entity properties
101
+ 4. All new exports are added to src/index.ts
102
+ 5. File paths follow the convention exactly
103
+ 6. No unnecessary files are created
104
+ 7. Code is consistent with existing patterns
105
+
106
+ **Important Reminders**:
107
+ - Only edit existing files when possible
108
+ - Never create documentation files unless explicitly requested
109
+ - Follow the CLAUDE.md instructions precisely
110
+ - Maintain consistency with the existing codebase structure
111
+ - Always use the established patterns from sundays-package-version as reference
112
+
113
+ When you receive a request, first analyze the entity structure needed, then systematically create each component following the established patterns. If any clarification is needed about field types or relationships, ask before proceeding.
@@ -0,0 +1,11 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm run migrate:create:*)",
5
+ "Bash(npm run migrate:deploy:*)",
6
+ "Bash(npm run build:*)"
7
+ ],
8
+ "deny": [],
9
+ "ask": []
10
+ }
11
+ }
@@ -0,0 +1,8 @@
1
+ SQL_HOST=localhost
2
+ SQL_PORT=5432
3
+ SQL_USER=postgres
4
+ SQL_PASSWORD=
5
+ SQL_DB_NAME=mydb
6
+
7
+ # Set to 'false' to disable SSL certificate verification (not recommended for production)
8
+ # SQL_REJECT_UNAUTHORIZED=false
@@ -0,0 +1,106 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## File Structure Conventions
6
+
7
+ **Interfaces**: All interfaces should be placed in `src/interfaces/{entity}/{entity}.interfaces.ts`
8
+ - Example: `src/interfaces/company/company.interfaces.ts`
9
+
10
+ **DAOs**: All DAO classes should be placed in `src/dao/{entity}/{entity}.dao.ts`
11
+ - Example: `src/dao/company/company.dao.ts`
12
+
13
+ This convention maintains consistency with the existing structure (e.g., sundays-package-version).
14
+
15
+ ## Common Development Commands
16
+
17
+ **Build**: `npm run build` - Compiles TypeScript to JavaScript in the `dist` directory
18
+
19
+ **Format**: `npm run format` - Formats code using Prettier
20
+
21
+ **Test**: `npm test` - Runs Jest tests
22
+
23
+ **Clean Build**: `npm run clean` - Removes dist, formats code, and rebuilds
24
+
25
+ **Database Migrations**:
26
+ - Create migration: `npm run migrate:create` - Creates a new migration file in TypeScript
27
+ - Run migrations: `npm run migrate:deploy` - Applies pending migrations
28
+
29
+ **Database Seeds**:
30
+ - Create seed: `npm run seed:create` - Creates a new seed file in TypeScript
31
+ - Run seeds: `npm run seed:run` - Executes seed files
32
+
33
+ ## Architecture Overview
34
+
35
+ This is a Knex.js database module (`@dupin/knex-v2`) that provides a PostgreSQL connection manager and data access layer.
36
+
37
+ **Key Components**:
38
+
39
+ 1. **KnexManager** (`src/KnexConnection.ts`): Singleton pattern for managing database connections
40
+ - Handles connection pooling with configurable min/max connections
41
+ - Uses environment variables for database configuration (SQL_HOST, SQL_USER, SQL_PASSWORD, SQL_DB_NAME, SQL_PORT)
42
+ - Supports SSL connections with `rejectUnauthorized: false`
43
+
44
+ 2. **DAO Pattern**: Data Access Objects implement the `IBaseDAO<T>` interface
45
+ - Example: `SundaysPackageVersionDAO` provides CRUD operations
46
+ - All DAOs use the shared KnexManager connection
47
+ - Includes pagination support via `IDataPaginator`
48
+
49
+ 3. **Database Configuration** (`knexfile.ts`): Supports development, staging, and production environments
50
+ - All environments use PostgreSQL client
51
+ - Configuration reads from environment variables
52
+ - Migration table: `knex_migrations`
53
+
54
+ 4. **Type System**:
55
+ - Interfaces in `src/interfaces/` define data models
56
+ - Common types in `src/d.types.ts` (IBaseDAO, IDataPaginator)
57
+ - All exports centralized in `src/index.ts`
58
+
59
+ **Environment Requirements**:
60
+ - SQL_HOST: PostgreSQL host
61
+ - SQL_USER: Database user
62
+ - SQL_PASSWORD: Database password
63
+ - SQL_DB_NAME: Database name
64
+ - SQL_PORT: Database port (defaults to 5432)
65
+
66
+ ## DAO Implementation Patterns
67
+
68
+ ### Join Pattern for Related Entities
69
+
70
+ When implementing DAOs that need to include related entities, use PostgreSQL's `to_jsonb()` function for clean and efficient joins:
71
+
72
+ ```typescript
73
+ async getById(id: number): Promise<IEntity | null> {
74
+ const result = await this._knex("entity as e")
75
+ .leftJoin("related as r", "e.relatedId", "r.id")
76
+ .select("e.*", this._knex.raw("to_jsonb(r.*) as related"))
77
+ .where("e.id", id)
78
+ .first();
79
+ return result || null;
80
+ }
81
+ ```
82
+
83
+ **Key Points:**
84
+ - Use table aliases for clarity (`as e`, `as r`)
85
+ - `to_jsonb(r.*)` automatically converts the joined row to JSON
86
+ - Returns `null` if no related entity is found (with leftJoin)
87
+ - No manual mapping required - PostgreSQL handles the conversion
88
+
89
+ **For paginated results:**
90
+ ```typescript
91
+ const query = this._knex("entity as e")
92
+ .leftJoin("related as r", "e.relatedId", "r.id")
93
+ .select("e.*", this._knex.raw("to_jsonb(r.*) as related"));
94
+
95
+ const data = await query
96
+ .clone()
97
+ .limit(limit)
98
+ .offset(offset)
99
+ .orderBy("e.id", "desc");
100
+ ```
101
+
102
+ ## Known Issues and Solutions
103
+
104
+ **Migration Error "require is not defined"**: The knexfile.ts uses ES module syntax. If you encounter this error, ensure the file uses:
105
+ - `import dotenv from "dotenv"` instead of `require("dotenv")`
106
+ - `export default config` instead of `module.exports = config`
@@ -0,0 +1,33 @@
1
+ import type { Knex } from "knex";
2
+ import dotenv from "dotenv";
3
+ dotenv.config();
4
+
5
+ const isLocalhost = process.env.SQL_HOST === 'localhost' || process.env.SQL_HOST === '127.0.0.1';
6
+ const rejectUnauthorized = process.env.SQL_REJECT_UNAUTHORIZED !== 'false';
7
+
8
+ const sharedConfig: Knex.Config = {
9
+ client: "postgresql",
10
+ connection: {
11
+ database: process.env.SQL_DB_NAME,
12
+ user: process.env.SQL_USER,
13
+ password: process.env.SQL_PASSWORD,
14
+ host: process.env.SQL_HOST,
15
+ port: process.env.SQL_PORT ? +process.env.SQL_PORT : 5432,
16
+ ssl: isLocalhost ? false : { rejectUnauthorized },
17
+ },
18
+ pool: {
19
+ min: 2,
20
+ max: 10,
21
+ },
22
+ migrations: {
23
+ tableName: "knex_migrations",
24
+ },
25
+ };
26
+
27
+ const config: { [key: string]: Knex.Config } = {
28
+ development: sharedConfig,
29
+ staging: sharedConfig,
30
+ production: sharedConfig,
31
+ };
32
+
33
+ export default config;
File without changes
@@ -0,0 +1,13 @@
1
+ import type { Knex } from "knex";
2
+
3
+ export async function up(knex: Knex): Promise<void> {
4
+ await knex.schema.createTable("sundays_package_version", (table) => {
5
+ table.increments("id").primary();
6
+ table.string("versionName").notNullable();
7
+ table.timestamps(true, true); // created_at, updated_at
8
+ });
9
+ }
10
+
11
+ export async function down(knex: Knex): Promise<void> {
12
+ await knex.schema.dropTableIfExists("sundays_package_version");
13
+ }
@@ -0,0 +1,11 @@
1
+ import { Knex } from "knex";
2
+
3
+ export async function seed(knex: Knex): Promise<void> {
4
+ // Deletes ALL existing entries
5
+ await knex("sundays_package_version").del();
6
+
7
+ // Inserts seed entries
8
+ await knex("sundays_package_version").insert([
9
+ { versionName: "1.0.0" }
10
+ ]);
11
+ }
@@ -0,0 +1,74 @@
1
+ import { knex, Knex } from 'knex';
2
+
3
+ class KnexManager {
4
+ private static knexInstance: Knex<any, unknown[]> | null = null;
5
+
6
+ /**
7
+ * Open a new connection. Reuse the already existing one if there's any.
8
+ */
9
+ static async connect(
10
+ config?: Knex.Config,
11
+ connections?: number
12
+ ): Promise<Knex<any, unknown[]>> {
13
+ if (!KnexManager.knexInstance) {
14
+ const isLocalhost = process.env.SQL_HOST === 'localhost' || process.env.SQL_HOST === '127.0.0.1';
15
+ const rejectUnauthorized = process.env.SQL_REJECT_UNAUTHORIZED !== 'false';
16
+ const defaultConfig = {
17
+ client: 'pg',
18
+ connection: {
19
+ host: process.env.SQL_HOST,
20
+ user: process.env.SQL_USER,
21
+ password: process.env.SQL_PASSWORD,
22
+ database: process.env.SQL_DB_NAME,
23
+ port: Number(process.env.SQL_PORT) || 5432,
24
+ ssl: isLocalhost ? false : { rejectUnauthorized },
25
+ },
26
+ pool: {
27
+ min: 1,
28
+ max: connections || 15,
29
+ idleTimeoutMillis: 20000,
30
+ acquireTimeoutMillis: 30000,
31
+ },
32
+ migrations: {
33
+ tableName: 'knex_migrations',
34
+ },
35
+ };
36
+ KnexManager.knexInstance = knex(config || defaultConfig);
37
+ try {
38
+ await KnexManager.knexInstance.raw('SELECT 1');
39
+ console.info(`Knex connection established`);
40
+ } catch (error) {
41
+ console.error(`Failed to establish Knex connection:`, error);
42
+ KnexManager.knexInstance = null;
43
+ throw error;
44
+ }
45
+ }
46
+
47
+ return KnexManager.knexInstance;
48
+ }
49
+
50
+ /**
51
+ * Returns the active connection.
52
+ */
53
+ static getConnection(): Knex<any, unknown[]> {
54
+ if (!KnexManager.knexInstance) {
55
+ throw new Error(
56
+ 'Knex connection has not been established. Call connect() first.'
57
+ );
58
+ }
59
+ return KnexManager.knexInstance;
60
+ }
61
+
62
+ /**
63
+ * Closes the connection and destroys the instance.
64
+ */
65
+ static async disconnect(): Promise<void> {
66
+ if (KnexManager.knexInstance) {
67
+ await KnexManager.knexInstance.destroy();
68
+ KnexManager.knexInstance = null;
69
+ console.info(`Knex connection closed`);
70
+ }
71
+ }
72
+ }
73
+
74
+ export default KnexManager;
@@ -0,0 +1,18 @@
1
+ export interface IBaseDAO<T> {
2
+ create(item: T): Promise<T>;
3
+ getById(id: number): Promise<T | null>;
4
+ getByUuid(uuid: string): Promise<T | null>;
5
+ update(id: number, item: Partial<T>): Promise<T | null>;
6
+ delete(id: number): Promise<boolean>;
7
+ getAll(page: number, limit: number): Promise<IDataPaginator<T>>;
8
+ }
9
+
10
+ export interface IDataPaginator<T> {
11
+ success: boolean;
12
+ data: T[];
13
+ page: number;
14
+ limit: number;
15
+ count: number;
16
+ totalCount: number;
17
+ totalPages: number;
18
+ }
@@ -0,0 +1,71 @@
1
+ import { Knex } from "knex";
2
+ import { IBaseDAO, IDataPaginator } from "../../d.types";
3
+ import { ISundaysPackageVersion } from "../../interfaces/sundays-package-version/sundays-package-version.interfaces";
4
+ import KnexManager from "../../KnexConnection";
5
+
6
+ export class SundaysPackageVersionDAO implements IBaseDAO<ISundaysPackageVersion> {
7
+ private _knex: Knex<any, unknown[]> = KnexManager.getConnection();
8
+
9
+ async create(item: ISundaysPackageVersion): Promise<ISundaysPackageVersion> {
10
+ const [created] = await this._knex("sundays_package_version").insert(item).returning("*");
11
+ return created;
12
+ }
13
+
14
+ async getById(id: number): Promise<ISundaysPackageVersion | null> {
15
+ const result = await this._knex("sundays_package_version")
16
+ .select("*")
17
+ .where("id", id)
18
+ .first();
19
+ return result || null;
20
+ }
21
+
22
+ async getByUuid(uuid: string): Promise<ISundaysPackageVersion | null> {
23
+ const result = await this._knex("sundays_package_version")
24
+ .select("*")
25
+ .where("uuid", uuid)
26
+ .first();
27
+ return result || null;
28
+ }
29
+
30
+ async update(id: number, item: Partial<ISundaysPackageVersion>): Promise<ISundaysPackageVersion | null> {
31
+ const [updated] = await this._knex("sundays_package_version")
32
+ .where({ id })
33
+ .update(item)
34
+ .returning("*");
35
+ return updated || null;
36
+ }
37
+
38
+ async delete(id: number): Promise<boolean> {
39
+ const result = await this._knex("sundays_package_version").where({ id }).del();
40
+ return result > 0;
41
+ }
42
+
43
+ async getAll(page: number, limit: number): Promise<IDataPaginator<ISundaysPackageVersion>> {
44
+ const safeLimit = Math.max(limit, 1);
45
+ const offset = (page - 1) * safeLimit;
46
+
47
+ const query = this._knex("sundays_package_version").select("*");
48
+
49
+ const [countResult] = await query.clone().clearSelect().count("* as count");
50
+ const totalCount = +countResult.count;
51
+ const data = await query.clone().limit(safeLimit).offset(offset).orderBy("id", "desc");
52
+
53
+ return {
54
+ success: true,
55
+ data,
56
+ page,
57
+ limit: safeLimit,
58
+ count: data.length,
59
+ totalCount,
60
+ totalPages: Math.ceil(totalCount / safeLimit),
61
+ };
62
+ }
63
+
64
+ async getLatestVersion(): Promise<ISundaysPackageVersion | null> {
65
+ const result = await this._knex("sundays_package_version")
66
+ .select("*")
67
+ .orderBy("id", "desc")
68
+ .first();
69
+ return result || null;
70
+ }
71
+ }
@@ -0,0 +1,9 @@
1
+ // DAOs
2
+ export { SundaysPackageVersionDAO } from "./dao/sundays-package-version/sundays-package-version.dao";
3
+
4
+ // Interfaces
5
+ export { IDataPaginator } from "./d.types";
6
+ export { ISundaysPackageVersion } from "./interfaces/sundays-package-version/sundays-package-version.interfaces";
7
+
8
+ import KnexManager from './KnexConnection';
9
+ export { KnexManager };
@@ -0,0 +1,6 @@
1
+ export interface ISundaysPackageVersion {
2
+ id: number;
3
+ versionName: string;
4
+ createdAt: string;
5
+ updatedAt: string;
6
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "CommonJS",
4
+ "target": "ES2022",
5
+ "sourceMap": true,
6
+ "esModuleInterop": true,
7
+ "strict": true,
8
+ "declaration": true,
9
+ "rootDir": "./src",
10
+ "outDir": "./dist",
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true
13
+ },
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules", "dist"]
16
+ }
@@ -0,0 +1,159 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Module Template Overview
6
+
7
+ This is a basic npm module template created by the Sundays Framework SDK. It provides a minimal starting point for creating reusable Node.js modules.
8
+
9
+ ## Commands
10
+
11
+ ### Development
12
+
13
+ - `npm run build` - Compile TypeScript to JavaScript (output to dist/)
14
+ - `npm test` - Run tests (no test framework configured by default)
15
+ - `npm run format` - Format code (if Prettier is configured)
16
+
17
+ ### Publishing
18
+
19
+ - `npm run npm:publish` - Publish the module to npm registry
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ module/
25
+ ├── src/ # TypeScript source files
26
+ │ └── index.ts # Main entry point
27
+ ├── dist/ # Compiled JavaScript output (generated)
28
+ ├── tsconfig.json # TypeScript configuration
29
+ ├── package.json # Module metadata and dependencies
30
+ └── .gitignore # Git ignore patterns
31
+ ```
32
+
33
+ ## Configuration
34
+
35
+ ### TypeScript Setup
36
+
37
+ The module is configured with TypeScript for type safety:
38
+ - Source files in `src/`
39
+ - Compiled output to `dist/`
40
+ - Strict mode enabled
41
+ - ES2020 target with CommonJS modules
42
+ - Declaration files generated for TypeScript consumers
43
+
44
+ ### Package.json
45
+
46
+ Key fields to configure:
47
+ - `name`: Your module name (scoped or unscoped)
48
+ - `version`: Semantic version (start with 0.1.0)
49
+ - `description`: Brief description of the module
50
+ - `main`: Entry point (usually `dist/index.js`)
51
+ - `types`: TypeScript declarations (usually `dist/index.d.ts`)
52
+ - `author`: Your name or organization
53
+ - `license`: License type (MIT, ISC, etc.)
54
+
55
+ ## Getting Started
56
+
57
+ 1. **Initialize the module**:
58
+ ```bash
59
+ npm install
60
+ ```
61
+
62
+ 2. **Write your module code** in `src/index.ts`:
63
+ ```typescript
64
+ export function myFunction() {
65
+ return "Hello from my module!";
66
+ }
67
+
68
+ export class MyClass {
69
+ // Your implementation
70
+ }
71
+ ```
72
+
73
+ 3. **Build the module**:
74
+ ```bash
75
+ npm run build
76
+ ```
77
+
78
+ 4. **Test locally** before publishing:
79
+ ```bash
80
+ npm link
81
+ # In another project:
82
+ npm link your-module-name
83
+ ```
84
+
85
+ 5. **Publish to npm**:
86
+ ```bash
87
+ npm run npm:publish
88
+ ```
89
+
90
+ ## Best Practices
91
+
92
+ 1. **Export Strategy**: Use named exports for clarity
93
+ ```typescript
94
+ export { MyClass, myFunction, MyInterface };
95
+ ```
96
+
97
+ 2. **Type Definitions**: Always include TypeScript definitions
98
+ - Helps consumers with IntelliSense
99
+ - Prevents type-related bugs
100
+
101
+ 3. **Documentation**: Add JSDoc comments to exported functions/classes
102
+ ```typescript
103
+ /**
104
+ * Calculates the sum of two numbers
105
+ * @param a First number
106
+ * @param b Second number
107
+ * @returns The sum of a and b
108
+ */
109
+ export function add(a: number, b: number): number {
110
+ return a + b;
111
+ }
112
+ ```
113
+
114
+ 4. **Versioning**: Follow semantic versioning (semver)
115
+ - MAJOR: Breaking changes
116
+ - MINOR: New features (backward compatible)
117
+ - PATCH: Bug fixes
118
+
119
+ 5. **Testing**: Consider adding a test framework
120
+ - Jest for unit testing
121
+ - Include test scripts in package.json
122
+
123
+ 6. **Dependencies**: Keep dependencies minimal
124
+ - Use `dependencies` for runtime requirements
125
+ - Use `devDependencies` for build/test tools
126
+ - Consider marking some as `peerDependencies`
127
+
128
+ ## Common Module Patterns
129
+
130
+ ### Singleton Pattern
131
+ ```typescript
132
+ class MySingleton {
133
+ private static instance: MySingleton;
134
+
135
+ private constructor() {}
136
+
137
+ static getInstance(): MySingleton {
138
+ if (!MySingleton.instance) {
139
+ MySingleton.instance = new MySingleton();
140
+ }
141
+ return MySingleton.instance;
142
+ }
143
+ }
144
+ ```
145
+
146
+ ### Factory Pattern
147
+ ```typescript
148
+ export function createInstance(config: Config): MyClass {
149
+ return new MyClass(config);
150
+ }
151
+ ```
152
+
153
+ ### Plugin/Extension Pattern
154
+ ```typescript
155
+ export interface Plugin {
156
+ name: string;
157
+ install(app: any): void;
158
+ }
159
+ ```
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Sundays Framework Module
3
+ *
4
+ * Replace this with your module exports.
5
+ */
6
+
7
+ export const hello = (): string => {
8
+ return 'Hello from Sundays module';
9
+ };