mirror of
https://github.com/harivansh-afk/betterNAS.git
synced 2026-04-15 09:01:13 +00:00
init
This commit is contained in:
parent
4f174ec3a8
commit
db1dea097f
81 changed files with 6263 additions and 545 deletions
|
|
@ -12,6 +12,7 @@ Use it to keep the four product parts aligned:
|
|||
|
||||
## What belongs here
|
||||
|
||||
- OpenAPI source documents
|
||||
- shared TypeScript types
|
||||
- route constants
|
||||
- JSON schemas for payloads we want to validate outside TypeScript
|
||||
|
|
@ -28,6 +29,8 @@ Use it to keep the four product parts aligned:
|
|||
- current runtime scaffold for health and version
|
||||
- [`src/foundation.ts`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/src/foundation.ts)
|
||||
- first product-level entities and route constants for node, mount, and cloud flows
|
||||
- [`openapi/`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/openapi)
|
||||
- language-neutral source documents for future SDK generation
|
||||
- [`schemas/`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/schemas)
|
||||
- JSON schema mirrors for the first shared entities
|
||||
|
||||
|
|
|
|||
307
packages/contracts/openapi/betternas.v1.yaml
Normal file
307
packages/contracts/openapi/betternas.v1.yaml
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
openapi: 3.1.0
|
||||
info:
|
||||
title: betterNAS Foundation API
|
||||
version: 0.1.0
|
||||
summary: Foundation contract for node registration, export metadata, and profile issuance.
|
||||
servers:
|
||||
- url: http://localhost:8081
|
||||
paths:
|
||||
/health:
|
||||
get:
|
||||
operationId: getControlPlaneHealth
|
||||
responses:
|
||||
"200":
|
||||
description: Control-plane health
|
||||
/version:
|
||||
get:
|
||||
operationId: getControlPlaneVersion
|
||||
responses:
|
||||
"200":
|
||||
description: Control-plane version
|
||||
/api/v1/nodes/register:
|
||||
post:
|
||||
operationId: registerNode
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/NodeRegistrationRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Registered node
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/NasNode"
|
||||
/api/v1/nodes/{nodeId}/heartbeat:
|
||||
post:
|
||||
operationId: recordNodeHeartbeat
|
||||
parameters:
|
||||
- in: path
|
||||
name: nodeId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/NodeHeartbeatRequest"
|
||||
responses:
|
||||
"204":
|
||||
description: Heartbeat accepted
|
||||
/api/v1/exports:
|
||||
get:
|
||||
operationId: listExports
|
||||
responses:
|
||||
"200":
|
||||
description: Export list
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/StorageExport"
|
||||
/api/v1/mount-profiles/issue:
|
||||
post:
|
||||
operationId: issueMountProfile
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MountProfileRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Mount profile
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MountProfile"
|
||||
/api/v1/cloud-profiles/issue:
|
||||
post:
|
||||
operationId: issueCloudProfile
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CloudProfileRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Cloud profile
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CloudProfile"
|
||||
components:
|
||||
schemas:
|
||||
NasNode:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- machineId
|
||||
- displayName
|
||||
- agentVersion
|
||||
- status
|
||||
- lastSeenAt
|
||||
- directAddress
|
||||
- relayAddress
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
machineId:
|
||||
type: string
|
||||
displayName:
|
||||
type: string
|
||||
agentVersion:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
enum: [online, offline, degraded]
|
||||
lastSeenAt:
|
||||
type: string
|
||||
directAddress:
|
||||
type:
|
||||
- string
|
||||
- "null"
|
||||
relayAddress:
|
||||
type:
|
||||
- string
|
||||
- "null"
|
||||
StorageExport:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- nasNodeId
|
||||
- label
|
||||
- path
|
||||
- protocols
|
||||
- capacityBytes
|
||||
- tags
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
nasNodeId:
|
||||
type: string
|
||||
label:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
protocols:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
enum: [webdav]
|
||||
capacityBytes:
|
||||
type:
|
||||
- integer
|
||||
- "null"
|
||||
tags:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
MountProfile:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- exportId
|
||||
- protocol
|
||||
- displayName
|
||||
- mountUrl
|
||||
- readonly
|
||||
- credentialMode
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
exportId:
|
||||
type: string
|
||||
protocol:
|
||||
type: string
|
||||
enum: [webdav]
|
||||
displayName:
|
||||
type: string
|
||||
mountUrl:
|
||||
type: string
|
||||
readonly:
|
||||
type: boolean
|
||||
credentialMode:
|
||||
type: string
|
||||
enum: [session-token, app-password]
|
||||
CloudProfile:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- exportId
|
||||
- provider
|
||||
- baseUrl
|
||||
- path
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
exportId:
|
||||
type: string
|
||||
provider:
|
||||
type: string
|
||||
enum: [nextcloud]
|
||||
baseUrl:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
StorageExportInput:
|
||||
type: object
|
||||
required:
|
||||
- label
|
||||
- path
|
||||
- protocols
|
||||
- capacityBytes
|
||||
- tags
|
||||
properties:
|
||||
label:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
protocols:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
enum: [webdav]
|
||||
capacityBytes:
|
||||
type:
|
||||
- integer
|
||||
- "null"
|
||||
tags:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
NodeRegistrationRequest:
|
||||
type: object
|
||||
required:
|
||||
- machineId
|
||||
- displayName
|
||||
- agentVersion
|
||||
- directAddress
|
||||
- relayAddress
|
||||
- exports
|
||||
properties:
|
||||
machineId:
|
||||
type: string
|
||||
displayName:
|
||||
type: string
|
||||
agentVersion:
|
||||
type: string
|
||||
directAddress:
|
||||
type:
|
||||
- string
|
||||
- "null"
|
||||
relayAddress:
|
||||
type:
|
||||
- string
|
||||
- "null"
|
||||
exports:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/StorageExportInput"
|
||||
NodeHeartbeatRequest:
|
||||
type: object
|
||||
required:
|
||||
- nodeId
|
||||
- status
|
||||
- lastSeenAt
|
||||
properties:
|
||||
nodeId:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
enum: [online, offline, degraded]
|
||||
lastSeenAt:
|
||||
type: string
|
||||
MountProfileRequest:
|
||||
type: object
|
||||
required:
|
||||
- userId
|
||||
- deviceId
|
||||
- exportId
|
||||
properties:
|
||||
userId:
|
||||
type: string
|
||||
deviceId:
|
||||
type: string
|
||||
exportId:
|
||||
type: string
|
||||
CloudProfileRequest:
|
||||
type: object
|
||||
required:
|
||||
- userId
|
||||
- exportId
|
||||
- provider
|
||||
properties:
|
||||
userId:
|
||||
type: string
|
||||
exportId:
|
||||
type: string
|
||||
provider:
|
||||
type: string
|
||||
enum: [nextcloud]
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"openapi",
|
||||
"schemas"
|
||||
],
|
||||
"scripts": {
|
||||
|
|
@ -14,4 +15,3 @@
|
|||
"typecheck": "tsc --noEmit -p tsconfig.json"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
3
packages/eslint-config/README.md
Normal file
3
packages/eslint-config/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# `@betternas/eslint-config`
|
||||
|
||||
Collection of internal eslint configurations.
|
||||
32
packages/eslint-config/base.js
Normal file
32
packages/eslint-config/base.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import js from "@eslint/js";
|
||||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
import turboPlugin from "eslint-plugin-turbo";
|
||||
import tseslint from "typescript-eslint";
|
||||
import onlyWarn from "eslint-plugin-only-warn";
|
||||
|
||||
/**
|
||||
* A shared ESLint configuration for the repository.
|
||||
*
|
||||
* @type {import("eslint").Linter.Config[]}
|
||||
* */
|
||||
export const config = [
|
||||
js.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
plugins: {
|
||||
turbo: turboPlugin,
|
||||
},
|
||||
rules: {
|
||||
"turbo/no-undeclared-env-vars": "warn",
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
onlyWarn,
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ["dist/**"],
|
||||
},
|
||||
];
|
||||
57
packages/eslint-config/next.js
Normal file
57
packages/eslint-config/next.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import js from "@eslint/js";
|
||||
import { globalIgnores } from "eslint/config";
|
||||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
import tseslint from "typescript-eslint";
|
||||
import pluginReactHooks from "eslint-plugin-react-hooks";
|
||||
import pluginReact from "eslint-plugin-react";
|
||||
import globals from "globals";
|
||||
import pluginNext from "@next/eslint-plugin-next";
|
||||
import { config as baseConfig } from "./base.js";
|
||||
|
||||
/**
|
||||
* A custom ESLint configuration for libraries that use Next.js.
|
||||
*
|
||||
* @type {import("eslint").Linter.Config[]}
|
||||
* */
|
||||
export const nextJsConfig = [
|
||||
...baseConfig,
|
||||
js.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
...tseslint.configs.recommended,
|
||||
globalIgnores([
|
||||
// Default ignores of eslint-config-next:
|
||||
".next/**",
|
||||
"out/**",
|
||||
"build/**",
|
||||
"next-env.d.ts",
|
||||
]),
|
||||
{
|
||||
...pluginReact.configs.flat.recommended,
|
||||
languageOptions: {
|
||||
...pluginReact.configs.flat.recommended.languageOptions,
|
||||
globals: {
|
||||
...globals.serviceworker,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
"@next/next": pluginNext,
|
||||
},
|
||||
rules: {
|
||||
...pluginNext.configs.recommended.rules,
|
||||
...pluginNext.configs["core-web-vitals"].rules,
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
"react-hooks": pluginReactHooks,
|
||||
},
|
||||
settings: { react: { version: "detect" } },
|
||||
rules: {
|
||||
...pluginReactHooks.configs.recommended.rules,
|
||||
// React scope no longer necessary with new JSX transform.
|
||||
"react/react-in-jsx-scope": "off",
|
||||
},
|
||||
},
|
||||
];
|
||||
24
packages/eslint-config/package.json
Normal file
24
packages/eslint-config/package.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "@betternas/eslint-config",
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"exports": {
|
||||
"./base": "./base.js",
|
||||
"./next-js": "./next.js",
|
||||
"./react-internal": "./react-internal.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@next/eslint-plugin-next": "^16.2.0",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-only-warn": "^1.1.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-turbo": "^2.7.1",
|
||||
"globals": "^16.5.0",
|
||||
"typescript": "^5.9.2",
|
||||
"typescript-eslint": "^8.50.0"
|
||||
}
|
||||
}
|
||||
39
packages/eslint-config/react-internal.js
vendored
Normal file
39
packages/eslint-config/react-internal.js
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import js from "@eslint/js";
|
||||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
import tseslint from "typescript-eslint";
|
||||
import pluginReactHooks from "eslint-plugin-react-hooks";
|
||||
import pluginReact from "eslint-plugin-react";
|
||||
import globals from "globals";
|
||||
import { config as baseConfig } from "./base.js";
|
||||
|
||||
/**
|
||||
* A custom ESLint configuration for libraries that use React.
|
||||
*
|
||||
* @type {import("eslint").Linter.Config[]} */
|
||||
export const config = [
|
||||
...baseConfig,
|
||||
js.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
...tseslint.configs.recommended,
|
||||
pluginReact.configs.flat.recommended,
|
||||
{
|
||||
languageOptions: {
|
||||
...pluginReact.configs.flat.recommended.languageOptions,
|
||||
globals: {
|
||||
...globals.serviceworker,
|
||||
...globals.browser,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
"react-hooks": pluginReactHooks,
|
||||
},
|
||||
settings: { react: { version: "detect" } },
|
||||
rules: {
|
||||
...pluginReactHooks.configs.recommended.rules,
|
||||
// React scope no longer necessary with new JSX transform.
|
||||
"react/react-in-jsx-scope": "off",
|
||||
},
|
||||
},
|
||||
];
|
||||
10
packages/sdk-ts/README.md
Normal file
10
packages/sdk-ts/README.md
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# `@betternas/sdk-ts`
|
||||
|
||||
Temporary TypeScript-facing SDK surface for the Next.js app.
|
||||
|
||||
The source of truth remains:
|
||||
|
||||
- [`packages/contracts/openapi`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/openapi)
|
||||
- [`packages/contracts/src`](/home/rathi/Documents/GitHub/betterNAS/packages/contracts/src)
|
||||
|
||||
Later this package should become generated code from the OpenAPI contracts.
|
||||
3
packages/sdk-ts/eslint.config.mjs
Normal file
3
packages/sdk-ts/eslint.config.mjs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import { config } from "@betternas/eslint-config/base";
|
||||
|
||||
export default config;
|
||||
24
packages/sdk-ts/package.json
Normal file
24
packages/sdk-ts/package.json
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "@betternas/sdk-ts",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"lint": "eslint . --max-warnings 0",
|
||||
"check-types": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@betternas/contracts": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@betternas/eslint-config": "*",
|
||||
"@betternas/typescript-config": "*",
|
||||
"@types/node": "^22.15.3",
|
||||
"eslint": "^9.39.1",
|
||||
"typescript": "5.9.2"
|
||||
}
|
||||
}
|
||||
1
packages/sdk-ts/src/index.ts
Normal file
1
packages/sdk-ts/src/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "@betternas/contracts";
|
||||
8
packages/sdk-ts/tsconfig.json
Normal file
8
packages/sdk-ts/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "@betternas/typescript-config/base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
19
packages/typescript-config/base.json
Normal file
19
packages/typescript-config/base.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"esModuleInterop": true,
|
||||
"incremental": false,
|
||||
"isolatedModules": true,
|
||||
"lib": ["es2022", "DOM", "DOM.Iterable"],
|
||||
"module": "NodeNext",
|
||||
"moduleDetection": "force",
|
||||
"moduleResolution": "NodeNext",
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "ES2022"
|
||||
}
|
||||
}
|
||||
12
packages/typescript-config/nextjs.json
Normal file
12
packages/typescript-config/nextjs.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"plugins": [{ "name": "next" }],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"allowJs": true,
|
||||
"jsx": "preserve",
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
9
packages/typescript-config/package.json
Normal file
9
packages/typescript-config/package.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "@betternas/typescript-config",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
7
packages/typescript-config/react-library.json
Normal file
7
packages/typescript-config/react-library.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx"
|
||||
}
|
||||
}
|
||||
4
packages/ui/eslint.config.mjs
Normal file
4
packages/ui/eslint.config.mjs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import { config } from "@betternas/eslint-config/react-internal";
|
||||
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
export default config;
|
||||
27
packages/ui/package.json
Normal file
27
packages/ui/package.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "@betternas/ui",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"exports": {
|
||||
"./*": "./src/*.tsx"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"lint": "eslint . --max-warnings 0",
|
||||
"generate:component": "turbo gen react-component",
|
||||
"check-types": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@betternas/eslint-config": "*",
|
||||
"@betternas/typescript-config": "*",
|
||||
"@types/node": "^22.15.3",
|
||||
"@types/react": "19.2.2",
|
||||
"@types/react-dom": "19.2.2",
|
||||
"eslint": "^9.39.1",
|
||||
"typescript": "5.9.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0"
|
||||
}
|
||||
}
|
||||
17
packages/ui/src/button.tsx
Normal file
17
packages/ui/src/button.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
|
||||
interface ButtonProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export const Button = ({ children, className, onClick }: ButtonProps) => {
|
||||
return (
|
||||
<button className={className} onClick={onClick} type="button">
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
22
packages/ui/src/card.tsx
Normal file
22
packages/ui/src/card.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { type JSX } from "react";
|
||||
|
||||
export function Card({
|
||||
className,
|
||||
title,
|
||||
children,
|
||||
href,
|
||||
}: {
|
||||
className?: string;
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
href: string;
|
||||
}): JSX.Element {
|
||||
return (
|
||||
<a className={className} href={href}>
|
||||
<h2>
|
||||
{title} <span>-></span>
|
||||
</h2>
|
||||
<p>{children}</p>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
11
packages/ui/src/code.tsx
Normal file
11
packages/ui/src/code.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { type JSX } from "react";
|
||||
|
||||
export function Code({
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}): JSX.Element {
|
||||
return <code className={className}>{children}</code>;
|
||||
}
|
||||
9
packages/ui/tsconfig.json
Normal file
9
packages/ui/tsconfig.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "@betternas/typescript-config/react-library.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue