nucleus-core-ts 0.10.0 → 0.10.2

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.
@@ -1,5 +1,36 @@
1
1
  import type { ApiResponse, EndpointAction, EndpointDefinition } from './types';
2
2
  export declare function createActionsFacade<TActions extends object>(endpoints: Record<string, unknown>, buildAction: (key: string) => TActions[keyof TActions]): TActions;
3
+ /**
4
+ * What a response does to an endpoint's cached state.
5
+ *
6
+ * Extracted so it can be tested without React: the hook needs a renderer, and
7
+ * the defect this guards lives entirely in this transition rather than in the
8
+ * rendering.
9
+ *
10
+ * The rule that matters is the failure branch. This store is built once at
11
+ * module scope, so its per-endpoint state is global to the browser session and
12
+ * survives client-side navigation. Leaving `data` alone on a failure left the
13
+ * last SUCCESSFUL answer readable under a different id.
14
+ *
15
+ * It was invisible while a missing row answered `200 {data:null}` — that
16
+ * overwrote the cache and the page rendered "not found". The moment a missing
17
+ * or out-of-scope row began answering 404, nothing cleared the cache and a
18
+ * detail page rendered THE PREVIOUS ROW under the new URL. Found by auditing a
19
+ * customer delivery before it upgraded: its announcements and employees are
20
+ * location-scoped, so "outside your scope" is the ordinary case, and an
21
+ * employee opening an announcement they may not see was shown the last one
22
+ * they could.
23
+ */
24
+ export declare function applyResponse(response: {
25
+ isSuccess?: boolean;
26
+ data?: unknown;
27
+ errors?: unknown;
28
+ code?: number | null;
29
+ }, fallbackError?: unknown): {
30
+ data: unknown;
31
+ error: unknown;
32
+ code: number | null;
33
+ };
3
34
  export declare function createApiHook<TEndpoints extends Record<string, EndpointDefinition>>(endpoints: TEndpoints, factory: <K extends keyof TEndpoints & string>(endpointKey: K, payload: TEndpoints[K]['_payload']) => Promise<ApiResponse<TEndpoints[K]['_success'], TEndpoints[K]['_error']>>): () => { [K in keyof TEndpoints]: EndpointAction<TEndpoints[K]["_payload"], TEndpoints[K]["_success"], TEndpoints[K]["_error"]>; };
4
35
  export type ApiHook<TEndpoints extends Record<string, EndpointDefinition>> = ReturnType<typeof createApiHook<TEndpoints>>;
5
36
  export type ApiActions<TEndpoints extends Record<string, EndpointDefinition>> = ReturnType<ApiHook<TEndpoints>>;
@@ -24,6 +24,15 @@ export declare function serverRequestId(response: {
24
24
  *
25
25
  * A response that already carries `data` is left exactly as it is; so is
26
26
  * anything that is not a plain object.
27
+ *
28
+ * `isSuccess` is destructured with `success` because it is the SAME FLAG under
29
+ * the API's other name (see `Server/response.ts`'s `withEnvelopeFlags`), and
30
+ * anything not named here falls into `rest` and is buried one level down as
31
+ * `data`. Left in `rest`, the server carrying both names would have turned
32
+ * `{success:false, message}` — which shapes to `{success, message}` and no
33
+ * `data` — into `{success, message, data:{isSuccess:false}}`, inventing a
34
+ * payload out of an envelope field. The same class of defect as the
35
+ * `requiresCaptcha` one the control-flag list above exists for.
27
36
  */
28
37
  export declare function normalizeResponseShape(response: unknown): unknown;
29
38
  export declare function createServerFactory<TEndpoints extends Record<string, EndpointDefinition>>(endpoints: TEndpoints, config: ServerFactoryConfig, getCookies: () => Promise<CookieStore>, getHeaders: () => Promise<HeadersStore>): <K extends keyof TEndpoints & string>(endpointKey: K, payload: TEndpoints[K]["_payload"]) => Promise<ApiResponse<TEndpoints[K]["_success"], TEndpoints[K]["_error"]>>;
@@ -565,10 +565,20 @@ export interface RevokeApiKeyPayload {
565
565
  id: string;
566
566
  reason?: string;
567
567
  }
568
+ /**
569
+ * The answer to a revoke — which is NOT a delete, and now says so.
570
+ *
571
+ * `data` was `null`, which left the caller with an HTTP DELETE, a 200 and no
572
+ * information: the natural reading is "gone", and the next `API_KEYS_DETAIL`
573
+ * answers 200 with the row. The row is kept on purpose — it is the audit record
574
+ * (`revokedAt`, `revokedReason`, `usageCount`, `lastUsedAt`) — so the answer
575
+ * carries it instead, with `isActive:false` and `revokedAt` set. See the note
576
+ * above the handler in `Nucleus/routes/auth/apiKeys/index.ts`.
577
+ */
568
578
  export interface RevokeApiKeyResponse {
569
579
  isSuccess: boolean;
570
580
  message: string;
571
- data: null;
581
+ data: ApiKeyListItem;
572
582
  }
573
583
  export declare const AUTH_ENDPOINT_CONFIGS: {
574
584
  login: {
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Ending every session an account is holding, from an administrator's action.
3
+ *
4
+ * Half of every "shut this account down" button lives here, and it is the half
5
+ * that used to be missing. Writing `is_locked = true` refuses the NEXT login;
6
+ * it says nothing about the browser that is already signed in, because the
7
+ * request path re-reads the session row on every request and never the user's
8
+ * own flags. Measured on a live install: a godmin locked an account, the next
9
+ * login was correctly refused 403 `Account is locked`, and the account's own
10
+ * `/auth/me` kept answering 200 — the lock bolted the front door with the
11
+ * intruder still inside.
12
+ *
13
+ * The password endpoints had already learned this ("Sessions opened with the
14
+ * old password end with it"), which is exactly what made the gap visible: two
15
+ * sibling administrator actions, one of which ended the sessions and one of
16
+ * which did not. So the statement lives in ONE place and every caller runs the
17
+ * same one, rather than each growing its own half-answer.
18
+ *
19
+ * A failure is reported as zero rather than thrown: the flag has already been
20
+ * written by the time this runs, and turning a completed lock into a 500 would
21
+ * send an administrator back to press a button that already worked. The number
22
+ * is returned so the answer can say `signedOut: 0` instead of rounding a
23
+ * half-done shutdown up to success.
24
+ */
25
+ type Executor = {
26
+ delete: (table: never) => {
27
+ where: (condition: never) => Promise<unknown>;
28
+ };
29
+ };
30
+ export interface RevokeUserSessionsDeps {
31
+ db: Executor | null | undefined;
32
+ /** The per-request sessions table; absent on an install that has none. */
33
+ sessionsTable: Record<string, unknown> | null | undefined;
34
+ /** Told what went wrong. Never rethrown — see above. */
35
+ onError?: (error: unknown) => void;
36
+ }
37
+ export declare function revokeUserSessions(deps: RevokeUserSessionsDeps, userIds: readonly string[]): Promise<number>;
38
+ export {};
@@ -1,6 +1,6 @@
1
1
  import type { Logger } from 'src/Services';
2
2
  import type { CohortContext, CohortRouteConfig } from '../types';
3
- export declare const handleDeactivateUsers: (db: NonNullable<CohortRouteConfig["db"]>, usersTable: NonNullable<CohortRouteConfig["usersTable"]>, logger: Logger) => (ctx: CohortContext<{
3
+ export declare const handleDeactivateUsers: (db: NonNullable<CohortRouteConfig["db"]>, usersTable: NonNullable<CohortRouteConfig["usersTable"]>, logger: Logger, sessionsTable: CohortRouteConfig["sessionsTable"]) => (ctx: CohortContext<{
4
4
  params: {
5
5
  id: string;
6
6
  };
@@ -12,6 +12,7 @@ export declare const handleDeactivateUsers: (db: NonNullable<CohortRouteConfig["
12
12
  success: boolean;
13
13
  data: {
14
14
  affected: number;
15
+ signedOut: number;
15
16
  };
16
17
  message?: undefined;
17
18
  }>;
@@ -6,6 +6,13 @@ export type CohortRouteConfig = {
6
6
  logger: Logger;
7
7
  cohortsTable: PgTable | null;
8
8
  usersTable: PgTable | null;
9
+ /**
10
+ * Needed by `deactivate-users`, which has to end the sessions of everybody it
11
+ * locks — otherwise the sweep bolts the door on a room full of people who are
12
+ * already inside. Optional: an install with no sessions table has nothing to
13
+ * end, and no other cohort handler reads it.
14
+ */
15
+ sessionsTable?: PgTable | null;
9
16
  rolesTable: PgTable | null;
10
17
  userRolesTable: PgTable | null;
11
18
  profilesTable: PgTable | null;
@@ -56,15 +56,31 @@ export declare function parseFormDataBody(body: unknown, config: StorageConfig):
56
56
  export declare function validateFile(file: File, config: StorageConfig): {
57
57
  valid: boolean;
58
58
  error?: string;
59
+ rejected?: boolean;
59
60
  };
60
61
  export declare function setStorageProvider(provider: StorageProvider | null): void;
61
62
  export declare function getStorageProvider(): StorageProvider | null;
62
63
  export declare function uploadFile(file: File, config: StorageConfig, subFolder?: string): Promise<FileUploadResult>;
63
64
  export declare function uploadFiles(files: File[], config: StorageConfig, subFolder?: string): Promise<{
64
65
  success: FileUploadResult[];
66
+ /**
67
+ * `rejected` separates "we refused your file" from "the upload broke".
68
+ *
69
+ * Both used to be one shape, and the route answered 500 to both — so a
70
+ * caller sending a .bin to an install that allows images was told the SERVER
71
+ * had failed. Measured on the preview:
72
+ *
73
+ * POST /files application/octet-stream
74
+ * 500 {"message":"File upload failed","errors":[{"error":"File type
75
+ * application/octet-stream is not in allowed list"}]}
76
+ *
77
+ * A 5xx is what an error-rate alarm counts, so every user picking the wrong
78
+ * file type read as an outage.
79
+ */
65
80
  failed: {
66
81
  file: string;
67
82
  error: string;
83
+ rejected?: boolean;
68
84
  }[];
69
85
  }>;
70
86
  /**
@@ -63,6 +63,73 @@ export interface ResponseSet {
63
63
  }
64
64
  /** A fresh `set` for one request. */
65
65
  export declare function createResponseSet(): ResponseSet;
66
+ /**
67
+ * ONE API, TWO NAMES FOR THE SAME FLAG — carried together rather than chosen
68
+ * between.
69
+ *
70
+ * Measured on the booted product (the widest config: auth, sessions, api-keys,
71
+ * config, secrets, integrations, monitoring, backup, chat, notifications,
72
+ * payment, storage, tenant), 342 declared routes walked anonymous and again
73
+ * with a real session. Which key the answer carried:
74
+ *
75
+ * anonymous signed-in
76
+ * `success` only 4 252
77
+ * `isSuccess` only 331 26
78
+ * BOTH already 0 9
79
+ * neither (health, subs, 5 55
80
+ * the validation envelope)
81
+ *
82
+ * The split is not a stray route. `auth`, `sessions`, the generic entity CRUD,
83
+ * chat, notifications and the shared admin refusal say `success`; `api-keys`,
84
+ * `nucleus/config`, `secrets`, `integrations`, `monitoring`, `auth/check` and
85
+ * the tenant subdomain check say `isSuccess` — and so does the refusal envelope
86
+ * this release standardised (`{isSuccess,message,status,errors,data}`, built in
87
+ * the returned-Error branch below, in `inboundGuard`, and in the tenant/CSRF/
88
+ * error middleware). Driven end to end, one login and one API key:
89
+ *
90
+ * POST /auth/login 200 {data,success}
91
+ * GET /auth/me 200 {data,success}
92
+ * POST /auth/api-keys 200 {data,isSuccess,message}
93
+ * GET /auth/api-keys 200 {data,isSuccess}
94
+ * DELETE /auth/api-keys/x 200 {data,isSuccess,message}
95
+ * GET /auth/api-keys 401 {data,errors,isSuccess,message,status}
96
+ *
97
+ * So a client walking one flow needs two checks, and either one alone is
98
+ * `undefined` on half of it.
99
+ *
100
+ * WHY BOTH, rather than picking the winner. Both names have live readers, and
101
+ * they are in THIS package:
102
+ *
103
+ * `success` the shipped `fe` components — `fe/types/index.ts`,
104
+ * `LoginForm.tsx`, `PendingTab.tsx` — read `body.success`, and
105
+ * `Client/ApiCaller`'s `normalizeResponseShape` keys its whole
106
+ * `{success, …rest} -> {success, message, data}` reshaping on it
107
+ * `isSuccess` `Client/ApiCaller/types.ts`'s `ApiResponse`, and
108
+ * `Services/Authorization/Middleware`, which reads
109
+ * `{isSuccess, message, data}` off a remote IDP's `/auth/check`
110
+ *
111
+ * Renaming either one silently breaks the other's readers on a release that
112
+ * says nothing about it — a host app's `if (!body.success)` starts falling
113
+ * through on every refusal, which is the failure mode that does not throw. So
114
+ * neither is taken away: every product envelope now answers with BOTH, same
115
+ * value, and any one check a consumer already writes keeps working.
116
+ *
117
+ * There is precedent in the product for exactly this, arrived at
118
+ * independently: `routes/shared/adminGuard.ts`'s privileged guard already
119
+ * answers `{isSuccess:false, success:false, …}`, and the surface census already
120
+ * pins `data,isSuccess,message,success` as one of the product's envelopes.
121
+ *
122
+ * Kept as one decision in one place rather than at 350 call sites, for the same
123
+ * reason the returned-Error envelope below is: the sites are a moving target
124
+ * and the rule is not.
125
+ *
126
+ * DELIBERATELY CONSERVATIVE. Only an OWN, BOOLEAN flag is mirrored, and only
127
+ * when its twin is absent. An answer carrying neither — `/health`'s
128
+ * `{status,timestamp}`, `POST /subs/:topic`'s `{status}` — is not given one: it
129
+ * never claimed to be an envelope, and inventing a flag for it would make this
130
+ * a reshaping rather than a rename-safety net.
131
+ */
132
+ export declare function withEnvelopeFlags(body: Record<string, unknown>): Record<string, unknown>;
66
133
  /**
67
134
  * Resolve a handler's return value into the response that goes on the wire.
68
135
  *
@@ -57,6 +57,24 @@ export declare const OPTIONAL_KIND: unique symbol;
57
57
  export declare function prepare(schema: TSchema | undefined, value: unknown, on: ValidationTarget): unknown;
58
58
  export type ValidationTarget = 'body' | 'query' | 'params';
59
59
  export interface ValidationFailure {
60
+ /**
61
+ * The success flag, under both names the API uses — see
62
+ * `Server/response.ts`'s `withEnvelopeFlags` for the census and for why both
63
+ * are carried rather than one being chosen.
64
+ *
65
+ * This body is hand-serialised in `router.ts` (Elysia pretty-printed this one
66
+ * body and no other, and that was measured byte for byte), so it never passes
67
+ * the central mirror and has to carry the flags itself. It was the last
68
+ * answer on the surface carrying NEITHER: 31 of the signed-in walk's answers
69
+ * were 422s on which `body.success` and `body.isSuccess` both read
70
+ * `undefined` — precisely the "a client cannot write one check" this change
71
+ * is about.
72
+ *
73
+ * `type: 'validation'` stays first-class and unchanged; a client that
74
+ * discriminates on it keeps working, it simply no longer HAS to.
75
+ */
76
+ isSuccess: false;
77
+ success: false;
60
78
  type: 'validation';
61
79
  on: ValidationTarget;
62
80
  property: string;
@@ -1783,8 +1783,29 @@ export interface NucleusConfigOptions {
1783
1783
  };
1784
1784
  }
1785
1785
  export type SchemaTableRegistry = Record<string, any>;
1786
+ /**
1787
+ * The shape a consumer reads off the wire — `ListResponse`, `SingleResponse`,
1788
+ * `MeResponse`, `LoginSuccess` and the rest of `Client/ApiCaller/types.ts` are
1789
+ * all this type.
1790
+ *
1791
+ * `isSuccess` is OPTIONAL and `success` is not, and the asymmetry is the point
1792
+ * rather than an oversight.
1793
+ *
1794
+ * The server carries both names for this one flag — `Server/response.ts`'s
1795
+ * `withEnvelopeFlags` has the measurement and the argument — so the field is
1796
+ * always there on an answer from a current build. Declaring it REQUIRED would
1797
+ * make every hand-written literal in a consumer's tests and mocks stop
1798
+ * compiling on upgrade, for a field they may never read; declaring it optional
1799
+ * lets `res.isSuccess` be written without a cast and keeps `res.success` the
1800
+ * one a caller can rely on without a narrowing check.
1801
+ *
1802
+ * Which to read: either. They hold the same value on every answer the product
1803
+ * gives, and the surface walk asserts that on all 1040 of them.
1804
+ */
1786
1805
  export type StandardReturn<T> = {
1787
1806
  success: boolean;
1807
+ /** The same flag under the API's other name — see the note above. */
1808
+ isSuccess?: boolean;
1788
1809
  message?: string;
1789
1810
  data?: T;
1790
1811
  error?: Error | string;
package/package.json CHANGED
@@ -1,126 +1,126 @@
1
1
  {
2
- "name": "nucleus-core-ts",
3
- "version": "0.10.0",
4
- "description": "Production-ready, enterprise-grade TypeScript framework for building multi-tenant APIs",
5
- "author": "Hidayet Can Özcan <hidayetcan@gmail.com>",
6
- "license": "SEE LICENSE IN LICENSE",
7
- "keywords": [
8
- "backend",
9
- "framework",
10
- "drizzle",
11
- "typescript"
12
- ],
13
- "files": [
14
- "bin",
15
- "dist",
16
- "schemas",
17
- "scripts",
18
- "infra/templates",
19
- "infra/scripts/generate-project.ts",
20
- "src/system.tables.json",
21
- "src/Services/SchemaTables/resolveEntities.ts",
22
- "src/Services/Logger/auditTaxonomy.ts",
23
- "public",
24
- "LICENSE"
25
- ],
26
- "module": "dist/index.js",
27
- "type": "module",
28
- "types": "dist/index.d.ts",
29
- "exports": {
30
- ".": {
31
- "types": "./dist/index.d.ts",
32
- "import": "./dist/index.js"
33
- },
34
- "./server": {
35
- "types": "./dist/server.d.ts",
36
- "import": "./dist/server.js"
37
- },
38
- "./client": {
39
- "types": "./dist/client.d.ts",
40
- "import": "./dist/client.js"
41
- },
42
- "./fe": {
43
- "types": "./dist/fe/index.d.ts",
44
- "import": "./dist/fe/index.js"
45
- },
46
- "./fe/auth": {
47
- "types": "./dist/fe/components/AuthGuard/index.d.ts",
48
- "import": "./dist/fe/components/AuthGuard/index.js"
49
- },
50
- "./proxy": {
51
- "types": "./dist/src/Client/Proxy/index.d.ts",
52
- "import": "./dist/src/Client/Proxy/index.js"
53
- }
54
- },
55
- "scripts": {
56
- "test": "bun test src scripts fe",
57
- "build": "bun run scripts/build.ts",
58
- "build:quick": "bun run build:js && bun run build:types",
59
- "build:js": "bun build ./index.ts ./server.ts ./client.ts ./fe/index.ts ./src/Client/Proxy/index.ts --outdir=dist --target=bun --format=esm --splitting --minify --external react --external react-dom --external gsap --external @gsap/react --external h-state --external drizzle-orm --external drizzle-kit --external ioredis --external googleapis --external @dapr/dapr --external pg --external @xyflow/react --external @xyflow/system --external @azure/communication-email --external nodemailer --external @azure/identity --external stripe --external sharp",
60
- "build:types": "tsc --declaration --emitDeclarationOnly --outDir dist --skipLibCheck",
61
- "version:patch": "bun run scripts/version.ts patch",
62
- "version:minor": "bun run scripts/version.ts minor",
63
- "version:major": "bun run scripts/version.ts major",
64
- "publish:npm": "bun run scripts/publish.ts",
65
- "publish:dry": "bun run scripts/publish.ts --dry-run",
66
- "release": "bun run version:patch && bun run publish:npm",
67
- "release:minor": "bun run version:minor && bun run publish:npm",
68
- "release:major": "bun run version:major && bun run publish:npm",
69
- "generate:schemas": "bun run scripts/generate-types-schema.ts",
70
- "lint": "biome check . --write",
71
- "lint:fix": "biome check --config-path ./biome.json --write",
72
- "prepublishOnly": "bun run scripts/verify-publishable.ts"
73
- },
74
- "bin": {
75
- "nucleus-core-ts": "./bin/cli.ts",
76
- "nucleus": "./bin/cli.ts",
77
- "nucleus-generate": "./bin/cli.ts"
78
- },
79
- "devDependencies": {
80
- "@biomejs/biome": "2.5.10",
81
- "googleapis": "^171.4.0",
82
- "@types/bun": "latest",
83
- "@types/pg": "latest",
84
- "@types/react": "latest",
85
- "@happy-dom/global-registrator": "^20.11.2",
86
- "@types/react-dom": "latest",
87
- "bun-plugin-tailwind": "latest",
88
- "drizzle-kit": "latest",
89
- "javascript-obfuscator": "latest",
90
- "lucide-react": "latest",
91
- "nodemailer": "^9.0.3"
92
- },
93
- "peerDependencies": {
94
- "typescript": "latest",
95
- "@dapr/dapr": "latest",
96
- "react": "latest",
97
- "react-dom": "latest",
98
- "pg": "latest",
99
- "tailwindcss": "latest",
100
- "tailwind-merge": "latest",
101
- "clsx": "latest",
102
- "googleapis": "*"
103
- },
104
- "dependencies": {
105
- "@sinclair/typebox": "0.34.47",
106
- "@gsap/react": "latest",
107
- "@simplewebauthn/server": "^13.3.0",
108
- "@xyflow/react": "latest",
109
- "drizzle-orm": "latest",
110
- "gsap": "latest",
111
- "h-state": "latest",
112
- "ioredis": "latest",
113
- "reflect-metadata": "^0.2.2"
114
- },
115
- "optionalDependencies": {
116
- "@azure/communication-email": "latest",
117
- "@marsaud/smb2": "^0.18.0",
118
- "sharp": "^0.33.0",
119
- "stripe": "latest"
120
- },
121
- "peerDependenciesMeta": {
122
- "googleapis": {
123
- "optional": true
124
- }
125
- }
2
+ "name": "nucleus-core-ts",
3
+ "version": "0.10.2",
4
+ "description": "Production-ready, enterprise-grade TypeScript framework for building multi-tenant APIs",
5
+ "author": "Hidayet Can Özcan <hidayetcan@gmail.com>",
6
+ "license": "SEE LICENSE IN LICENSE",
7
+ "keywords": [
8
+ "backend",
9
+ "framework",
10
+ "drizzle",
11
+ "typescript"
12
+ ],
13
+ "files": [
14
+ "bin",
15
+ "dist",
16
+ "schemas",
17
+ "scripts",
18
+ "infra/templates",
19
+ "infra/scripts/generate-project.ts",
20
+ "src/system.tables.json",
21
+ "src/Services/SchemaTables/resolveEntities.ts",
22
+ "src/Services/Logger/auditTaxonomy.ts",
23
+ "public",
24
+ "LICENSE"
25
+ ],
26
+ "module": "dist/index.js",
27
+ "type": "module",
28
+ "types": "dist/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js"
33
+ },
34
+ "./server": {
35
+ "types": "./dist/server.d.ts",
36
+ "import": "./dist/server.js"
37
+ },
38
+ "./client": {
39
+ "types": "./dist/client.d.ts",
40
+ "import": "./dist/client.js"
41
+ },
42
+ "./fe": {
43
+ "types": "./dist/fe/index.d.ts",
44
+ "import": "./dist/fe/index.js"
45
+ },
46
+ "./fe/auth": {
47
+ "types": "./dist/fe/components/AuthGuard/index.d.ts",
48
+ "import": "./dist/fe/components/AuthGuard/index.js"
49
+ },
50
+ "./proxy": {
51
+ "types": "./dist/src/Client/Proxy/index.d.ts",
52
+ "import": "./dist/src/Client/Proxy/index.js"
53
+ }
54
+ },
55
+ "scripts": {
56
+ "test": "bun test src scripts fe",
57
+ "build": "bun run scripts/build.ts",
58
+ "build:quick": "bun run build:js && bun run build:types",
59
+ "build:js": "bun build ./index.ts ./server.ts ./client.ts ./fe/index.ts ./src/Client/Proxy/index.ts --outdir=dist --target=bun --format=esm --splitting --minify --external react --external react-dom --external gsap --external @gsap/react --external h-state --external drizzle-orm --external drizzle-kit --external ioredis --external googleapis --external @dapr/dapr --external pg --external @xyflow/react --external @xyflow/system --external @azure/communication-email --external nodemailer --external @azure/identity --external stripe --external sharp",
60
+ "build:types": "tsc --declaration --emitDeclarationOnly --outDir dist --skipLibCheck",
61
+ "version:patch": "bun run scripts/version.ts patch",
62
+ "version:minor": "bun run scripts/version.ts minor",
63
+ "version:major": "bun run scripts/version.ts major",
64
+ "publish:npm": "bun run scripts/publish.ts",
65
+ "publish:dry": "bun run scripts/publish.ts --dry-run",
66
+ "release": "bun run version:patch && bun run publish:npm",
67
+ "release:minor": "bun run version:minor && bun run publish:npm",
68
+ "release:major": "bun run version:major && bun run publish:npm",
69
+ "generate:schemas": "bun run scripts/generate-types-schema.ts",
70
+ "lint": "biome check . --write",
71
+ "lint:fix": "biome check --config-path ./biome.json --write",
72
+ "prepublishOnly": "bun run scripts/verify-publishable.ts"
73
+ },
74
+ "bin": {
75
+ "nucleus-core-ts": "./bin/cli.ts",
76
+ "nucleus": "./bin/cli.ts",
77
+ "nucleus-generate": "./bin/cli.ts"
78
+ },
79
+ "devDependencies": {
80
+ "@biomejs/biome": "2.5.10",
81
+ "googleapis": "^171.4.0",
82
+ "@types/bun": "latest",
83
+ "@types/pg": "latest",
84
+ "@types/react": "latest",
85
+ "@happy-dom/global-registrator": "^20.11.2",
86
+ "@types/react-dom": "latest",
87
+ "bun-plugin-tailwind": "latest",
88
+ "drizzle-kit": "latest",
89
+ "javascript-obfuscator": "latest",
90
+ "lucide-react": "latest",
91
+ "nodemailer": "^9.0.3"
92
+ },
93
+ "peerDependencies": {
94
+ "typescript": "latest",
95
+ "@dapr/dapr": "latest",
96
+ "react": "latest",
97
+ "react-dom": "latest",
98
+ "pg": "latest",
99
+ "tailwindcss": "latest",
100
+ "tailwind-merge": "latest",
101
+ "clsx": "latest",
102
+ "googleapis": "*"
103
+ },
104
+ "dependencies": {
105
+ "@sinclair/typebox": "0.34.47",
106
+ "@gsap/react": "latest",
107
+ "@simplewebauthn/server": "^13.3.0",
108
+ "@xyflow/react": "latest",
109
+ "drizzle-orm": "latest",
110
+ "gsap": "latest",
111
+ "h-state": "latest",
112
+ "ioredis": "latest",
113
+ "reflect-metadata": "^0.2.2"
114
+ },
115
+ "optionalDependencies": {
116
+ "@azure/communication-email": "latest",
117
+ "@marsaud/smb2": "^0.18.0",
118
+ "sharp": "^0.33.0",
119
+ "stripe": "latest"
120
+ },
121
+ "peerDependenciesMeta": {
122
+ "googleapis": {
123
+ "optional": true
124
+ }
125
+ }
126
126
  }