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.
- package/dist/.build-ok +1 -1
- package/dist/client.js +2 -2
- package/dist/index.js +13 -13
- package/dist/server.js +13 -13
- package/dist/src/Client/ApiCaller/client.d.ts +31 -0
- package/dist/src/Client/ApiCaller/server.d.ts +9 -0
- package/dist/src/Client/ApiCaller/types.d.ts +11 -1
- package/dist/src/Nucleus/routes/auth/admin/revokeUserSessions.d.ts +38 -0
- package/dist/src/Nucleus/routes/auth/cohort/handlers/deactivateUsers.d.ts +2 -1
- package/dist/src/Nucleus/routes/auth/cohort/types.d.ts +7 -0
- package/dist/src/Nucleus/routes/storage/helpers.d.ts +16 -0
- package/dist/src/Server/response.d.ts +67 -0
- package/dist/src/Server/validate.d.ts +18 -0
- package/dist/src/types.d.ts +21 -0
- package/package.json +124 -124
|
@@ -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:
|
|
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;
|
package/dist/src/types.d.ts
CHANGED
|
@@ -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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
}
|