diff --git a/.all-contributorsrc b/.all-contributorsrc
new file mode 100644
index 0000000..3acba6e
--- /dev/null
+++ b/.all-contributorsrc
@@ -0,0 +1,15 @@
+{
+ "files": [
+ "README.md"
+ ],
+ "imageSize": 100,
+ "commit": false,
+ "contributors": [],
+ "contributorsPerLine": 7,
+ "projectName": "rc",
+ "projectOwner": "NodeSecure",
+ "repoType": "database",
+ "repoHost": "https://github.com",
+ "skipCi": true,
+ "commitConvention": "angular"
+}
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..4cb1507
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,14 @@
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+end_of_line = lf
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..e69de29
diff --git a/.gitignore b/.gitignore
index 6704566..cf658a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -102,3 +102,5 @@ dist
# TernJS port file
.tern-port
+
+temp/
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 0000000..43c97e7
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1 @@
+package-lock=false
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..20cf6b9
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,46 @@
+# Contributing to NodeSecure
+
+Contributions to NodeSecure include code, documentation, answering user questions and
+running the project's infrastructure
+
+The NodeSecure project welcomes all contributions from anyone willing to work in
+good faith with other contributors and the community. No contribution is too
+small and all contributions are valued.
+
+This guide explains the process for contributing to the NodeSecure project's.
+
+## [Code of Conduct](https://github.com/NodeSecure/Governance/blob/main/CODE_OF_CONDUCT.md)
+
+The NodeSecure project has a
+[Code of Conduct](https://github.com/NodeSecure/Governance/blob/main/CODE_OF_CONDUCT.md)
+that *all* contributors are expected to follow. This code describes the
+*minimum* behavior expectations for all contributors.
+
+See [details on our policy on Code of Conduct](https://github.com/NodeSecure/Governance/blob/main/COC_POLICY.md).
+
+
+## Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+* (a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+* (b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+* (c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+* (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
diff --git a/README.md b/README.md
index ee28bc8..ac35ead 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,25 @@
# database
NodeSecure Security Database
+
+## Contributors ✨
+
+
+[![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-)
+
+
+Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
+
+
+
+
+
+
+
+
+
+
+
+## License
+
+MIT
+
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..3700d62
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,5 @@
+# Reporting Security Issues
+
+To report a security issue, please [publish a private security advisory](https://github.com/NodeSecure/rc/database/advisories) with a description of the issue, the steps you took to create the issue, affected versions, and, if known, mitigations for the issue.
+
+Our vulnerability management team will respond within one week. If the issue is confirmed as a vulnerability, we will open a Security Advisory and acknowledge your contributions as part of it. This project follows a 90 day disclosure timeline.
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..b0d4ef6
--- /dev/null
+++ b/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "@nodesecure/database",
+ "version": "1.0.0",
+ "description": "NodeSecure Security Database",
+ "main": "index.js",
+ "type": "module",
+ "scripts": {
+ "build": "tsc",
+ "start:http": "node --env-file=.env ./dist/api/server.js",
+ "test": "glob -c \"tsx --test\" \"./test/**/*.spec.ts\"",
+ "coverage": "c8 -r html npm test"
+ },
+ "engines": {
+ "node": "=>20"
+ },
+ "keywords": [
+ "database",
+ "npm",
+ "registry",
+ "secure",
+ "security"
+ ],
+ "author": "GENTILHOMME Thomas ",
+ "license": "MIT",
+ "devDependencies": {
+ "@nodesecure/eslint-config": "^1.9.0",
+ "@types/node": "^20.12.11",
+ "c8": "^9.1.0",
+ "eslint": "^8.57.0",
+ "glob": "^10.3.12",
+ "tsx": "^4.9.3",
+ "typescript": "^5.4.5"
+ },
+ "dependencies": {
+ "@nodesecure/npm-registry-sdk": "^2.1.1",
+ "fastify": "^4.27.0",
+ "fastify-plugin": "^4.5.1",
+ "pino": "^9.0.0",
+ "pino-pretty": "^11.0.0",
+ "zod": "^3.23.8"
+ }
+}
diff --git a/src/api/app.ts b/src/api/app.ts
new file mode 100644
index 0000000..b4bb9b5
--- /dev/null
+++ b/src/api/app.ts
@@ -0,0 +1,37 @@
+// Import Third-party Dependencies
+import fastify, { FastifyInstance } from "fastify";
+
+// Import Internal Dependencies
+import * as endpoints from "./endpoints/index.js";
+
+// Import Plugins
+import { npmAuthenticationPlugin } from "./plugins/npmAuthentication.js";
+import { standardRegistryPlugin } from "./plugins/registry.js";
+
+export function createServer(): FastifyInstance {
+ const server = fastify({
+ logger: {
+ transport: {
+ target: "pino-pretty"
+ }
+ }
+ });
+ server.register(npmRegistryEndpoints);
+
+ return server;
+}
+
+/**
+ * @see https://github.com/npm/registry/blob/main/docs/REGISTRY-API.md#endpoints
+ */
+async function npmRegistryEndpoints(
+ server: FastifyInstance
+) {
+ server.register(standardRegistryPlugin);
+ server.register(npmAuthenticationPlugin);
+
+ server.get("/", endpoints.metadata);
+ server.get("/:package", endpoints.packument);
+ server.get("/:package/:version", endpoints.packumentVersion);
+ server.get("/-/v1/search", endpoints.search);
+}
diff --git a/src/api/endpoints/index.ts b/src/api/endpoints/index.ts
new file mode 100644
index 0000000..9bfcf61
--- /dev/null
+++ b/src/api/endpoints/index.ts
@@ -0,0 +1,4 @@
+export * from "./metadata.js";
+export * from "./package.js";
+export * from "./packageWithVersion.js";
+export * from "./search.js";
diff --git a/src/api/endpoints/metadata.ts b/src/api/endpoints/metadata.ts
new file mode 100644
index 0000000..bf68498
--- /dev/null
+++ b/src/api/endpoints/metadata.ts
@@ -0,0 +1,23 @@
+// Import Third-party Dependencies
+import { NpmRegistryMetadata } from "@nodesecure/npm-registry-sdk";
+
+/**
+ * TODO: rework this with real metadata
+ * - Maybe return a Partial
+ * and remove useless keys! (not sure what's the impact).
+ */
+export async function metadata(): Promise {
+ return {
+ db_name: "nodesecure_db",
+ doc_count: 0,
+ doc_del_count: 0,
+ update_seq: 0,
+ purge_seq: 0,
+ compact_running: false,
+ disk_size: 0,
+ data_size: 0,
+ instance_start_time: process.uptime().toString(),
+ disk_format_version: 6,
+ committed_update_seq: 0
+ }
+}
diff --git a/src/api/endpoints/package.ts b/src/api/endpoints/package.ts
new file mode 100644
index 0000000..6ea5bda
--- /dev/null
+++ b/src/api/endpoints/package.ts
@@ -0,0 +1,19 @@
+// Import Third-party Dependencies
+import { FastifyRequest } from "fastify";
+
+interface PackumentEndpoint {
+ Params: {
+ package: string;
+ }
+}
+
+export async function packument(
+ request: FastifyRequest
+) {
+ const data = await request.server.registry.package(
+ request.params.package,
+ request.npmAuthenticationOptions
+ );
+
+ return data;
+}
diff --git a/src/api/endpoints/packageWithVersion.ts b/src/api/endpoints/packageWithVersion.ts
new file mode 100644
index 0000000..b48dd58
--- /dev/null
+++ b/src/api/endpoints/packageWithVersion.ts
@@ -0,0 +1,21 @@
+// Import Third-party Dependencies
+import { FastifyRequest } from "fastify";
+
+interface PackumentVersionEndpoint {
+ Params: {
+ package: string;
+ version: string;
+ }
+}
+
+export async function packumentVersion(
+ request: FastifyRequest
+) {
+ const data = await request.server.registry.packageWithVersion(
+ request.params.package,
+ request.params.version,
+ request.npmAuthenticationOptions
+ );
+
+ return data;
+}
diff --git a/src/api/endpoints/search.ts b/src/api/endpoints/search.ts
new file mode 100644
index 0000000..a00a0c2
--- /dev/null
+++ b/src/api/endpoints/search.ts
@@ -0,0 +1,18 @@
+// Import Third-party Dependencies
+import { FastifyRequest } from "fastify";
+import { SearchCriteria } from "@nodesecure/npm-registry-sdk";
+
+interface SearchEndpoint {
+ Querystring: SearchCriteria;
+}
+
+export async function search(
+ request: FastifyRequest
+) {
+ const data = await request.server.registry.search(
+ request.query,
+ request.npmAuthenticationOptions
+ );
+
+ return data;
+}
diff --git a/src/api/plugins/npmAuthentication.ts b/src/api/plugins/npmAuthentication.ts
new file mode 100644
index 0000000..89c2da4
--- /dev/null
+++ b/src/api/plugins/npmAuthentication.ts
@@ -0,0 +1,41 @@
+// Import Third-party Dependencies
+import {
+ FastifyInstance,
+ FastifyRequest,
+ FastifyPluginAsync
+} from "fastify";
+import fp from "fastify-plugin";
+
+// Import Internal Dependencies
+import { NpmAuthenticationOptions } from "../services/NpmRegistry.js";
+
+// CONSTANTS
+const kNpmTokenHeaderName = "x-npm-token";
+
+async function npmAuthenticationPrehandler(
+ request: FastifyRequest
+) {
+ const token = request.headers[kNpmTokenHeaderName];
+ if (typeof token === "string") {
+ request.npmAuthenticationOptions = {
+ token
+ };
+ }
+}
+
+async function authentication(
+ server: FastifyInstance
+) {
+ server.addHook("preHandler", npmAuthenticationPrehandler);
+}
+
+export const npmAuthenticationPlugin: FastifyPluginAsync = fp(
+ authentication,
+ { name: "npmAuthentication" }
+);
+
+declare module "fastify" {
+ interface FastifyRequest {
+ npmAuthenticationOptions?: NpmAuthenticationOptions;
+ }
+}
diff --git a/src/api/plugins/registry.ts b/src/api/plugins/registry.ts
new file mode 100644
index 0000000..3550098
--- /dev/null
+++ b/src/api/plugins/registry.ts
@@ -0,0 +1,22 @@
+// Import Third-party Dependencies
+import {
+ FastifyInstance,
+ FastifyPluginAsync
+} from "fastify";
+import fp from "fastify-plugin";
+
+// Import Internal Dependencies
+import { StandardRegistry, NpmRegistry } from "../services/NpmRegistry.js";
+
+export const standardRegistryPlugin: FastifyPluginAsync = fp(
+ async function(server: FastifyInstance) {
+ server.decorate("registry", new NpmRegistry());
+ },
+ { name: "registry" }
+);
+
+declare module "fastify" {
+ interface FastifyInstance {
+ registry: StandardRegistry;
+ }
+}
diff --git a/src/api/server.ts b/src/api/server.ts
new file mode 100644
index 0000000..e93d444
--- /dev/null
+++ b/src/api/server.ts
@@ -0,0 +1,23 @@
+// Import Third-party Dependencies
+import z from "zod";
+
+// Import Internal Dependencies
+import { createServer } from "./app.js";
+
+// CONSTANTS
+const kServerEnvSchema = z.object({
+ host: z.string().optional(),
+ port: z.coerce.number().optional().default(0)
+});
+
+const env = kServerEnvSchema.parse(process.env);
+const server = createServer();
+
+server.listen(env, function httpListeningCallback(err, addr) {
+ if (err) {
+ server.log.error(err);
+ process.exit(1);
+ }
+
+ server.log.info(`Server listening on ${addr}`);
+});
diff --git a/src/api/services/NpmRegistry.ts b/src/api/services/NpmRegistry.ts
new file mode 100644
index 0000000..9b4f3da
--- /dev/null
+++ b/src/api/services/NpmRegistry.ts
@@ -0,0 +1,44 @@
+// Import Third-party Dependencies
+import {
+ packument,
+ packumentVersion,
+ search,
+
+ type PackumentOptions,
+ type Packument,
+ type PackumentVersion,
+ type SearchCriteria,
+ type SearchResult
+} from "@nodesecure/npm-registry-sdk";
+
+export interface StandardRegistry {
+ package: (name: string, options?: NpmAuthenticationOptions) => Promise;
+ packageWithVersion: (name: string, version: string, options?: NpmAuthenticationOptions) => Promise;
+ search: (criteria: SearchCriteria, options?: NpmAuthenticationOptions) => Promise;
+}
+
+export type NpmAuthenticationOptions = Pick;
+
+export class NpmRegistry implements StandardRegistry {
+ package(
+ name: string,
+ options?: NpmAuthenticationOptions
+ ) {
+ return packument(name, options);
+ }
+
+ packageWithVersion(
+ name: string,
+ version: string,
+ options?: NpmAuthenticationOptions
+ ) {
+ return packumentVersion(name, version, options);
+ }
+
+ search(
+ criteria: SearchCriteria,
+ options?: NpmAuthenticationOptions
+ ) {
+ return search(criteria, options);
+ }
+}
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..e69de29
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..aae92b3
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "declaration": true,
+ "strictNullChecks": true,
+ "target": "ES2022",
+ "outDir": "dist",
+ "module": "ES2022",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "skipDefaultLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "sourceMap": true,
+ "rootDir": "./src",
+ "types": ["node"]
+ },
+ "include": ["src"],
+ "exclude": ["node_modules", "dist"]
+}
\ No newline at end of file