{"_id":"@1matrix/config-loader","_rev":"5-7468ee41271ace21a6b36f5235a3b6f3","name":"@1matrix/config-loader","dist-tags":{"latest":"1.0.0"},"versions":{"0.1.0":{"name":"@1matrix/config-loader","version":"0.1.0","keywords":["config","configuration","github","webhook","hot-reload","web3","typescript"],"author":{"name":"OneMatrix"},"license":"MIT","_id":"@1matrix/config-loader@0.1.0","maintainers":[{"name":"hieu1m","email":"hieutt@1matrix.com"},{"name":"manhtv","email":"manhtv@1matrix.com"}],"dist":{"shasum":"1e16e07c6df158aa29691548fb98fb5c0d6fbdc8","tarball":"https://registry.npmjs.org/@1matrix/config-loader/-/config-loader-0.1.0.tgz","fileCount":54,"integrity":"sha512-4QRsNc+ImWIeDY+xc81jmoZCNQ+cjexyu4D8pu/6okLB9TuUh+fE/rJsca94CXufVOZ/vRvLxnsXv7j5FSsz2Q==","signatures":[{"sig":"MEYCIQDIMIWmkZmgEX6ir6OyOWK3BnnITqEeF4vgupFJO7WRzAIhALgDhikYYkpuw/oYjiUiNOV6/USdYmAVVkGBNSm2Zbmg","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":69264},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"943a3b358398851c8457f1bc1fc60b9d21268ee5","scripts":{"test":"jest","build":"tsc","test:watch":"jest --watch","build:watch":"tsc --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"manhtv","email":"manhtv@1matrix.com"},"_npmVersion":"11.6.2","description":"Hot-reloadable public configuration management for Apps with GitHub webhook integration","directories":{},"_nodeVersion":"24.11.1","dependencies":{"ajv":"^8.12.0","@octokit/rest":"^18.12.0","eventemitter3":"^5.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","nock":"^13.5.0","express":"^4.18.2","ts-jest":"^29.1.1","supertest":"^6.3.4","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","@types/express":"^4.17.21","@ethersproject/strings":"^5.7.0","@ethersproject/keccak256":"^5.7.0"},"_npmOperationalInternal":{"tmp":"tmp/config-loader_0.1.0_1766474953362_0.015505825861812594","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@1matrix/config-loader","version":"0.1.1","keywords":["config","configuration","github","webhook","hot-reload","typescript"],"author":{"name":"OneMatrix"},"license":"MIT","_id":"@1matrix/config-loader@0.1.1","maintainers":[{"name":"hieu1m","email":"hieutt@1matrix.com"},{"name":"manhtv","email":"manhtv@1matrix.com"}],"dist":{"shasum":"6f4a46dbd122472db4547c879e8c6df2418e94ef","tarball":"https://registry.npmjs.org/@1matrix/config-loader/-/config-loader-0.1.1.tgz","fileCount":54,"integrity":"sha512-WbS7KyAh/l4hU1qksba4jYbMnLyRCfntBgC7SkbD/CXSvuJ0wdVFzS6uP/pYML9V3BH1Nb7fXfXPf08xBdtgwQ==","signatures":[{"sig":"MEYCIQD0yRPg9pH/Yg7SWQgP8rULzMHJkr2eckXUf1Zkae6zNAIhAMMgr/4syvl/Hk/XpFkZ/pVfzHaggW6gmQsTsADPtzif","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":69249},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"943a3b358398851c8457f1bc1fc60b9d21268ee5","scripts":{"test":"jest","build":"tsc","test:watch":"jest --watch","build:watch":"tsc --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"manhtv","email":"manhtv@1matrix.com"},"_npmVersion":"11.6.2","description":"Hot-reloadable public configuration management for Apps with GitHub webhook integration","directories":{},"_nodeVersion":"24.11.1","dependencies":{"ajv":"^8.12.0","@octokit/rest":"^18.12.0","eventemitter3":"^5.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","nock":"^13.5.0","express":"^4.18.2","ts-jest":"^29.1.1","supertest":"^6.3.4","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","@types/express":"^4.17.21","@ethersproject/strings":"^5.7.0","@ethersproject/keccak256":"^5.7.0"},"_npmOperationalInternal":{"tmp":"tmp/config-loader_0.1.1_1766475043757_0.8851099187221794","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@1matrix/config-loader","version":"0.1.2","keywords":["config","configuration","github","webhook","hot-reload","typescript"],"author":{"name":"OneMatrix"},"license":"MIT","_id":"@1matrix/config-loader@0.1.2","maintainers":[{"name":"hieu1m","email":"hieutt@1matrix.com"},{"name":"manhtv","email":"manhtv@1matrix.com"}],"dist":{"shasum":"15527ad94ae22764339696b6b5cd297a7407f94d","tarball":"https://registry.npmjs.org/@1matrix/config-loader/-/config-loader-0.1.2.tgz","fileCount":54,"integrity":"sha512-8qSTgo02TcMrhk0t+B51ux95NYISYmeUTE3N8fyWxYP67SGaFTAKa9lemqRGHYaFD93UXUL9Y2E0py3FVXguqA==","signatures":[{"sig":"MEYCIQCP4wkG1zon8jEw26xSx+8uE/4pBVjIaCaTWK15XonpNgIhAJGHWMXtZuTM173aiCQF/lqgiEs+XMZ0mU1XJveq6rSk","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":69091},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"bba3a578712258852e9da202dbb82c3e1f2e1f1a","scripts":{"test":"jest","build":"tsc","test:watch":"jest --watch","build:watch":"tsc --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"manhtv","email":"manhtv@1matrix.com"},"_npmVersion":"11.6.2","description":"Hot-reloadable public configuration management for Apps with GitHub webhook integration","directories":{},"_nodeVersion":"24.11.1","dependencies":{"ajv":"^8.12.0","@octokit/rest":"^18.12.0","eventemitter3":"^5.0.1"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","nock":"^13.5.0","express":"^4.18.2","ts-jest":"^29.1.1","supertest":"^6.3.4","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","@types/express":"^4.17.21","@ethersproject/strings":"^5.7.0","@ethersproject/keccak256":"^5.7.0"},"_npmOperationalInternal":{"tmp":"tmp/config-loader_0.1.2_1766475408683_0.7224299869833288","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@1matrix/config-loader","version":"0.1.3","keywords":["config","configuration","github","webhook","hot-reload","typescript"],"author":{"name":"OneMatrix"},"license":"MIT","_id":"@1matrix/config-loader@0.1.3","maintainers":[{"name":"hieu1m","email":"hieutt@1matrix.com"},{"name":"manhtv","email":"manhtv@1matrix.com"}],"dist":{"shasum":"8e701e2f700d1d0f2c5fd7e18a4337e317847011","tarball":"https://registry.npmjs.org/@1matrix/config-loader/-/config-loader-0.1.3.tgz","fileCount":82,"integrity":"sha512-cXdTCnpl0rUr7QoszfUraZaOWfK2fiwgPyd+sEMnTIt3L9pHcoTtuof29ZLoNjdfE8YlLu1EJ86d0kC9tPDJPA==","signatures":[{"sig":"MEUCIQDr3OJayFQoR/D5o/UDUgakgzSMS3xTAOHCMUFyTB5PgQIgIQTJpJb8mFKQS0gTAELdqaZDqmv3+EhXQsMcBCjk27c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":99860},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"b374b1a6a2215cfd7cfdc667d4a06fdd8831cded","scripts":{"test":"jest","build":"tsc","test:watch":"jest --watch","build:watch":"tsc --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"manhtv","email":"manhtv@1matrix.com"},"_npmVersion":"11.6.2","description":"Hot-reloadable public configuration management for Apps with GitHub webhook integration","directories":{},"_nodeVersion":"24.11.1","dependencies":{"ajv":"^8.12.0","@octokit/rest":"^18.12.0","eventemitter3":"^5.0.1","@ethersproject/strings":"^5.7.0","@ethersproject/keccak256":"^5.7.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","nock":"^13.5.0","express":"^4.18.2","ts-jest":"^29.1.1","supertest":"^6.3.4","typescript":"^5.3.3","@types/jest":"^29.5.11","@types/node":"^20.10.6","@types/express":"^4.17.21"},"_npmOperationalInternal":{"tmp":"tmp/config-loader_0.1.3_1766543212423_0.1306350280557318","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@1matrix/config-loader","version":"1.0.0","description":"Hot-reloadable public configuration management for Apps with GitHub webhook integration","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","build:watch":"tsc --watch","test":"jest","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"keywords":["config","configuration","github","webhook","hot-reload","typescript"],"author":{"name":"OneMatrix"},"license":"MIT","dependencies":{"@ethersproject/keccak256":"^5.7.0","@ethersproject/strings":"^5.7.0","@octokit/rest":"^18.12.0","ajv":"^8.12.0","eventemitter3":"^5.0.1"},"devDependencies":{"@types/express":"^4.17.21","@types/jest":"^29.5.11","@types/node":"^20.10.6","express":"^4.18.2","jest":"^29.7.0","nock":"^13.5.0","supertest":"^6.3.4","ts-jest":"^29.1.1","typescript":"^5.3.3"},"engines":{"node":">=16.0.0"},"gitHead":"ab30c54f5cbf2f45a343d61369bf37dc9b7b533a","_id":"@1matrix/config-loader@1.0.0","_nodeVersion":"24.11.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-F4oS/mis96tQsobvkoGPoFMmDFJ0EfF5yoyq92B+VBdUJWOVtURz+2qNgq7C17FLUBP47/69OgdeMREhHsg6dg==","shasum":"bec20b43c6d38d98053fd6cbaba9de98fba815d8","tarball":"https://registry.npmjs.org/@1matrix/config-loader/-/config-loader-1.0.0.tgz","fileCount":82,"unpackedSize":107215,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEV/flDF4xXYhFWLEdRNiGcumcPJxR0gUgpD3eV8rGdqAiEAnolq6zjuWExYNAhWZKwo6ZKdfnyakH1Yx7qWdBSHNa4="}]},"_npmUser":{"name":"manhtv","email":"manhtv@1matrix.com"},"directories":{},"maintainers":[{"name":"hieu1m","email":"hieutt@1matrix.com"},{"name":"manhtv","email":"manhtv@1matrix.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/config-loader_1.0.0_1766631717343_0.00169956338195143"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-23T07:29:13.262Z","modified":"2025-12-25T03:01:57.795Z","0.1.0":"2025-12-23T07:29:13.494Z","0.1.1":"2025-12-23T07:30:43.891Z","0.1.2":"2025-12-23T07:36:48.823Z","0.1.3":"2025-12-24T02:26:52.593Z","1.0.0":"2025-12-25T03:01:57.579Z"},"author":{"name":"OneMatrix"},"license":"MIT","keywords":["config","configuration","github","webhook","hot-reload","typescript"],"description":"Hot-reloadable public configuration management for Apps with GitHub webhook integration","maintainers":[{"name":"hieu1m","email":"hieutt@1matrix.com"},{"name":"manhtv","email":"manhtv@1matrix.com"}],"readme":"# @1matrix/config-loader\n\nHot-reloadable public configuration management for Applications with GitHub webhook integration.\n\n## Features\n\n- ✅ **Hot Reloading**: Automatically update configurations without restarting your application\n- ✅ **GitHub Integration**: Fetch configurations from a dedicated GitHub repository\n- ✅ **Webhook Support**: Real-time updates via GitHub webhooks\n- ✅ **Polling Backup**: Periodic polling as a fallback mechanism\n- ✅ **Schema Validation**: JSON Schema validation for all configurations\n- ✅ **Environment Support**: Map NODE_ENV to different configuration directories\n- ✅ **Fail-safe Caching**: Local cache fallback when GitHub is unavailable\n- ✅ **TypeScript**: Full TypeScript support with type definitions\n- ✅ **Event-Driven**: Listen to configuration changes with EventEmitter\n- ✅ **Framework Adapters**: Built-in Express and Fastify support\n- ✅ **API Key Auth**: Ready-to-use API key authentication middleware\n\n## Installation\n\n```bash\npnpm add @1matrix/config-loader\n```\n\n## Quick Start\n\n### 1. Initialize ConfigLoader\n\n```typescript\nimport { ConfigLoader } from \"@1matrix/config-loader\";\n\n// Set NODE_ENV (required)\nprocess.env.NODE_ENV = \"production\";\n\nconst config = new ConfigLoader({\n\trepository: \"OneMatrixL1/public-configs\",\n\tbranch: \"main\",\n\tgithubToken: process.env.GITHUB_TOKEN,\n\twebhookSecret: process.env.GITHUB_WEBHOOK_SECRET,\n\n\t// Optional settings\n\tpollingInterval: 5 * 60 * 1000, // Optional: 5 minutes (disabled by default)\n\tenvMappings: { production: \"prod\", development: \"dev\" }, // Optional: map NODE_ENV values\n\tcacheFile: \"/tmp/config-loader-cache.json\", // Optional: default location\n\trequireInitialConfig: false, // Optional: false = permissive mode (default)\n});\n\nawait config.initialize();\n```\n\n### 2. Access Configuration\n\n```typescript\n// Get specific value\nconst apiKeyName = config.get(\"api-keys.a129f786...\");\n\n// Get with type inference\nconst handlers = config.get<string[]>(\"intent-handlers\", []);\n\n// Check if exists\nif (config.has(\"api-keys.some-hash\")) {\n\t// ...\n}\n\n// Get all configs\nconst allConfigs = config.getAll();\n```\n\n### 3. Listen to Updates\n\n```typescript\n// Listen to all updates\nconfig.on(\"update\", (newConfigs, changedKeys) => {\n\tconsole.log(\"Updated configs:\", changedKeys);\n});\n\n// Listen to specific config updates\nconfig.on(\"update:api-keys\", (newApiKeys) => {\n\tconsole.log(\"API keys changed\");\n});\n\n// Listen to validation errors\nconfig.on(\"validation-error\", (configName, errors) => {\n\tconsole.error(\"Validation failed:\", configName, errors);\n});\n\n// Listen to error events (for monitoring)\nconfig.on(\"error\", (errorEvent) => {\n\tconsole.error(\"Config error:\", {\n\t\tsource: errorEvent.source, // 'github' | 'cache' | 'validation'\n\t\tphase: errorEvent.phase, // 'initialize' | 'refresh' | 'polling'\n\t\terror: errorEvent.error,\n\t\tfallbackUsed: errorEvent.fallbackUsed,\n\t\ttimestamp: errorEvent.timestamp,\n\t});\n});\n```\n\n### 4. Set Up Webhook\n\n**Express:**\n\n```typescript\nimport express from \"express\";\nimport { createExpressWebhook } from \"@1matrix/config-loader\";\n\nconst app = express();\n\napp.post(\n\t\"/webhook/config\",\n\texpress.json(),\n\tcreateExpressWebhook(config, {\n\t\tonUpdate: (configs) => console.log(\"Updated via webhook\"),\n\t\tonError: (err) => console.error(err),\n\t})\n);\n```\n\n**Fastify:**\n\n```typescript\nimport Fastify from \"fastify\";\nimport { createFastifyWebhook } from \"@1matrix/config-loader\";\n\nconst fastify = Fastify();\n\nfastify.post(\"/webhook/config\", createFastifyWebhook(config, {\n\tonUpdate: (configs) => console.log(\"Updated via webhook\"),\n\tonError: (err) => console.error(err),\n}));\n```\n\n### 5. Protect Routes with API Key Authentication\n\n**Express:**\n\n```typescript\nimport { createExpressApiKeyAuth } from \"@1matrix/config-loader\";\n\n// Default: uses Keccak256 hashing (most common)\napp.use(\"/api\", createExpressApiKeyAuth(config));\n\n// If clients send pre-hashed keys (disable hashing)\napp.use(\"/api\", createExpressApiKeyAuth(config, { hashFn: null }));\n\napp.get(\"/api/protected\", (req, res) => {\n\tres.json({ authenticatedAs: req.apiKeyName });\n});\n```\n\n**Fastify:**\n\n```typescript\nimport { createFastifyApiKeyAuth } from \"@1matrix/config-loader\";\n\n// Default: uses Keccak256 hashing (most common)\nfastify.addHook(\"preHandler\", createFastifyApiKeyAuth(config));\n\n// If clients send pre-hashed keys (disable hashing)\nfastify.addHook(\"preHandler\", createFastifyApiKeyAuth(config, { hashFn: null }));\n\n// Or apply to specific routes\nfastify.get(\"/api/protected\", {\n\tpreHandler: createFastifyApiKeyAuth(config)\n}, async (request) => {\n\treturn { authenticatedAs: request.apiKeyName };\n});\n```\n\n## Configuration Repository Structure\n\nYour GitHub configuration repository should follow this structure:\n\n```\npublic-configs/\n├── schemas/\n│   ├── api-keys.schema.json\n│   ├── roles.schema.json\n│   └── intent-handlers.schema.json\n├── dev/\n│   ├── api-keys.json\n│   ├── roles.json\n│   └── intent-handlers.json\n├── staging/\n│   └── ...\n└── prod/\n    └── ...\n```\n\n### Example Configurations\n\n**`api/keys-dev.json`**\n\n```json\n{\n\t\"a129f7860d47c0630e6d06c153fe36711f25a31bfb4304dc6d2a79e609da0e96\": \"VNIDC\",\n\t\"b234c8971e58d1741f7e17d264gf47822g36b42cgc5415ed7e3b8a710eb1fa07\": \"SERVICE_2\"\n}\n```\n\n**`rabc/roles-dev.json`**\n\n```json\n{\n\t\"explorer.viewer\": [\n\t\t\"0xE61383556642AF1Bd7c5756b13f19A63Dc8601df\",\n\t\t\"0x7d5538fEe2CE89dA936ec29cC48386b6E7548FaB\"\n\t],\n\t\"admin\": [\"0x194f5b1755562966302Ef0BbF4349c842c60FC42\"]\n}\n```\n\n**`intent/handlers-dev.json`**\n\n```json\n[\n\t\"0x84f915BcbD5C1134BCb93a0f50D9D36E6D3b508c\",\n\t\"0x626b1E2458A9307E73A570c291bCd467216cc1D7\"\n]\n```\n\n### Example Schemas\n\n**`schemas/api-keys.schema.json`**\n\n```json\n{\n\t\"$schema\": \"http://json-schema.org/draft-07/schema#\",\n\t\"type\": \"object\",\n\t\"patternProperties\": {\n\t\t\"^[a-f0-9]{64}$\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"minLength\": 1\n\t\t}\n\t},\n\t\"additionalProperties\": false\n}\n```\n\n## Environment Variables\n\n### NODE_ENV (Required)\n\nThe `NODE_ENV` environment variable determines which configuration directory to load.\n\n```bash\nNODE_ENV=production node app.js\n```\n\nUse `envMappings` to map NODE_ENV values to configuration directories:\n\n```typescript\nconst config = new ConfigLoader({\n\trepository: \"owner/repo\",\n\tbranch: \"main\",\n\tenvMappings: {\n\t\tproduction: \"prod\",\n\t\tdevelopment: \"dev\",\n\t\tstaging: \"stg\",\n\t},\n});\n```\n\n### SKIP_AUTH (Optional)\n\nSet `SKIP_AUTH=true` to bypass authentication middleware (for testing only).\n\n```bash\nSKIP_AUTH=true NODE_ENV=test npm test\n```\n\n⚠️ **Warning:** If `SKIP_AUTH=true` in production, a warning will be logged to the console.\n\n## Configuration Options\n\n### ConfigLoaderOptions\n\n| Option                  | Type                      | Default                           | Description                                      |\n| ----------------------- | ------------------------- | --------------------------------- | ------------------------------------------------ |\n| `repository`            | `string`                  | **Required**                      | GitHub repository in `owner/repo` format         |\n| `branch`                | `string`                  | **Required**                      | Git branch to fetch from                         |\n| `githubToken`           | `string`                  | `undefined`                       | GitHub personal access token                     |\n| `webhookSecret`         | `string`                  | `undefined`                       | GitHub webhook secret for signature verification |\n| `envMappings`           | `Record<string, string>`  | `{}`                              | Map NODE_ENV values to config directories        |\n| `pollingInterval`       | `number`                  | `undefined` (disabled)            | Polling interval in milliseconds                 |\n| `cacheFile`             | `string`                  | `/tmp/config-loader-cache.json`   | Local cache file path                            |\n| `usePackageSchemas`     | `boolean`                 | `true`                            | Use embedded default schemas                     |\n| `requireInitialConfig`  | `boolean`                 | `false`                           | Throw error if no configs available on startup   |\n\n### Error Handling Modes\n\n**Permissive Mode** (`requireInitialConfig: false`, default):\n- Starts with empty configs if GitHub and cache both fail\n- Emits error events for monitoring\n- Application continues running\n\n**Strict Mode** (`requireInitialConfig: true`):\n- Throws error if no configs available on startup\n- Ensures application always has configuration data\n- Better for production deployments with critical config dependencies\n\n## API Reference\n\n### Framework Adapters\n\n#### `createExpressWebhook(configLoader, options?)`\n\nCreate Express middleware for handling GitHub webhook requests.\n\n**Parameters:**\n- `configLoader: ConfigLoader` - ConfigLoader instance\n- `options?: WebhookCoreOptions` - Optional webhook handler options\n  - `onUpdate?: (configs) => void` - Called when configs are updated\n  - `onError?: (error) => void` - Called on errors\n\n**Returns:** Express middleware function\n\n#### `createFastifyWebhook(configLoader, options?)`\n\nCreate Fastify route handler for GitHub webhook requests.\n\n**Parameters:** Same as `createExpressWebhook`\n\n**Returns:** Fastify route handler function\n\n#### `createExpressApiKeyAuth(configLoader, options?)`\n\nCreate Express middleware for API key authentication.\n\n**Parameters:**\n- `configLoader: ConfigLoader` - ConfigLoader instance\n- `options?: ExpressApiKeyAuthOptions`\n  - `headerName?: string` - Header to extract API key from (default: `x-api-key`)\n  - `hashFn?: (raw: string) => string` - Function to hash raw API keys\n  - `onError?: (req, res, error) => void` - Custom error handler\n  - `onSuccess?: (req, res, name) => void` - Custom success handler\n\n**Returns:** Express middleware function\n\n**Note:** Attaches `apiKeyName` to `req` object when authentication succeeds.\n\n#### `createFastifyApiKeyAuth(configLoader, options?)`\n\nCreate Fastify preHandler hook for API key authentication.\n\n**Parameters:**\n- `configLoader: ConfigLoader` - ConfigLoader instance\n- `options?: FastifyApiKeyAuthOptions`\n  - `headerName?: string` - Header to extract API key from (default: `x-api-key`)\n  - `hashFn?: (raw: string) => string` - Function to hash raw API keys\n  - `onError?: (request, reply, error) => void` - Custom error handler\n  - `onSuccess?: (request, reply, name) => void` - Custom success handler\n\n**Returns:** Fastify preHandler hook function\n\n**Note:** Attaches `apiKeyName` to `request` object when authentication succeeds.\n\n#### `verifyApiKey(configLoader, hashedKey)`\n\nLow-level API key verification utility (used internally by auth adapters).\n\n**Parameters:**\n- `configLoader: ConfigLoader` - ConfigLoader instance\n- `hashedKey: string | undefined` - Pre-hashed API key\n\n**Returns:** `ApiKeyVerificationResult`\n```typescript\n{\n  valid: boolean;\n  name?: string;      // API key name if valid\n  error?: string;     // Error message if invalid\n}\n```\n\n### ConfigLoader Options\n\n```typescript\ninterface ConfigLoaderOptions {\n\trepository: string; // GitHub repository (owner/repo)\n\tbranch: string; // Branch to fetch from\n\tgithubToken?: string; // GitHub personal access token\n\twebhookSecret?: string; // GitHub webhook secret\n\tenvMappings?: Record<string, string>; // NODE_ENV to directory mappings\n\tdefaultEnv?: string; // Default environment (default: 'dev')\n\tpollingInterval?: number; // Polling interval in ms (default: 300000)\n\tcacheFile?: string; // Cache file path (default: './config-cache.json')\n\tusePackageSchemas?: boolean; // Use built-in schemas (default: true)\n}\n```\n\n### Methods\n\n#### `async initialize(): Promise<void>`\n\nInitialize the config loader. Attempts to load from GitHub, falls back to cache if unavailable.\n\n#### `async refresh(): Promise<void>`\n\nManually refresh configurations from GitHub.\n\n#### `get<T>(path: string, defaultValue?: T): T | undefined`\n\nGet a configuration value by dot-notation path.\n\n#### `has(path: string): boolean`\n\nCheck if a configuration path exists.\n\n#### `getAll(): Record<string, any>`\n\nGet all configurations.\n\n#### `getCurrentEnvironment(): string`\n\nGet the current environment name.\n\n#### `getConfigNames(): string[]`\n\nGet names of all loaded configurations.\n\n#### `createWebhookHandler(options?: WebhookHandlerOptions): ExpressMiddleware`\n\nCreate an Express middleware for handling GitHub webhooks.\n\n#### `destroy(): void`\n\nClean up resources (stop polling, remove listeners).\n\n### Events\n\n#### `'update'`\n\nEmitted when configurations are updated.\n\n```typescript\nconfig.on(\n\t\"update\",\n\t(newConfigs: Record<string, any>, changedKeys: string[]) => {\n\t\t// Handle update\n\t}\n);\n```\n\n#### `'update:${configName}'`\n\nEmitted when a specific configuration is updated.\n\n```typescript\nconfig.on(\"update:api-keys\", (newApiKeys: any) => {\n\t// Handle API keys update\n});\n```\n\n#### `'validation-error'`\n\nEmitted when configuration validation fails.\n\n```typescript\nconfig.on(\"validation-error\", (configName: string, errors: any[]) => {\n\t// Handle validation error\n});\n```\n\n#### `'error'`\n\nEmitted when an error occurs.\n\n```typescript\nconfig.on(\"error\", (error: Error) => {\n\t// Handle error\n});\n```\n\n## GitHub Webhook Setup\n\n### 1. Create Webhook in GitHub Repository\n\n1. Go to your config repository → Settings → Webhooks → Add webhook\n2. Payload URL: `https://your-app.com/webhook/config-update`\n3. Content type: `application/json`\n4. Secret: Generate a strong random secret\n5. Events: Select \"Just the push event\"\n6. Active: ✅\n\n### 2. Configure Branch Protection\n\nEnsure only authorized users can update configs:\n\n1. Go to Settings → Branches → Add rule\n2. Branch name pattern: `main`\n3. Enable:\n   - Require pull request reviews (at least 1 approval)\n   - Require status checks before merging\n   - Restrict push access to admins\n\n### 3. Set Environment Variables\n\n```bash\nGITHUB_TOKEN=ghp_your_personal_access_token\nGITHUB_WEBHOOK_SECRET=your_webhook_secret\n```\n\n## Environment Mapping\n\nMap `NODE_ENV` values to configuration directories:\n\n```typescript\nconst config = new ConfigLoader({\n\t// ...\n\tenvMappings: {\n\t\tdev: \"dev\",\n\t\tdevelopment: \"dev\",\n\t\tdevelop: \"develop\",\n\t\tstg: \"stg\",\n\t\tstaging: \"staging\",\n\t\tprod: \"prod\",\n\t\tproduction: \"production\",\n\t},\n\tdefaultEnv: \"dev\",\n});\n```\n\n## Security Best Practices\n\n### ✅ DO\n\n- Store only hashed/public data in configurations (e.g., Keccak256 hashes)\n- Use environment variables for webhook secrets and GitHub tokens\n- Enable branch protection on configuration repository\n- Monitor `validation-error` events for malicious payloads\n- Set up alerts for repeated webhook validation failures\n\n### ❌ DON'T\n\n- Store raw API keys or passwords in configuration files\n- Expose webhook endpoints without signature validation\n- Allow direct pushes to main branch (require PRs)\n- Disable schema validation\n- Use weak webhook secrets\n\n## Testing\n\n```bash\n# Run tests\npnpm test\n\n# Run tests in watch mode\npnpm test:watch\n\n# Run tests with coverage\npnpm test:coverage\n```\n\n## Building\n\n```bash\n# Build TypeScript to JavaScript\npnpm build\n\n# Build and watch for changes\npnpm build:watch\n```\n\n## Examples\n\nSee the `examples/` directory for complete examples:\n\n- `basic-usage.ts`: Simple configuration loading\n- `express-integration.ts`: Full Express.js integration with webhooks\n\n## License\n\nMIT\n\n## Contributing\n\nContributions are welcome! Please open an issue or submit a pull request.\n\n## Support\n\nFor issues and questions, please open an issue on GitHub.\n","readmeFilename":"README.md"}