dn-react-router-toolkit 0.7.15 → 0.8.1
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/api/create_api_handler.d.mts +5 -4
- package/dist/api/create_api_handler.d.ts +5 -4
- package/dist/api/create_api_handler.js +0 -1
- package/dist/api/create_api_handler.mjs +0 -1
- package/dist/api/index.d.mts +1 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +13 -6
- package/dist/api/index.mjs +14 -7
- package/dist/api/item_api_handler.d.mts +8 -5
- package/dist/api/item_api_handler.d.ts +8 -5
- package/dist/api/item_api_handler.js +13 -5
- package/dist/api/item_api_handler.mjs +14 -6
- package/dist/crud/crud_loader.d.mts +6 -5
- package/dist/crud/crud_loader.d.ts +6 -5
- package/dist/crud/crud_loader.js +79 -38
- package/dist/crud/crud_loader.mjs +81 -39
- package/dist/crud/crud_page.d.mts +3 -2
- package/dist/crud/crud_page.d.ts +3 -2
- package/dist/crud/crud_page.js +279 -201
- package/dist/crud/crud_page.mjs +277 -205
- package/dist/crud/generate_handlers.d.mts +3 -2
- package/dist/crud/generate_handlers.d.ts +3 -2
- package/dist/crud/generate_pages.d.mts +2 -1
- package/dist/crud/generate_pages.d.ts +2 -1
- package/dist/crud/index.d.mts +5 -3
- package/dist/crud/index.d.ts +5 -3
- package/dist/crud/index.js +338 -219
- package/dist/crud/index.mjs +346 -232
- package/dist/post/index.js +71 -64
- package/dist/post/index.mjs +76 -74
- package/dist/post/post_form_page.js +71 -64
- package/dist/post/post_form_page.mjs +76 -74
- package/dist/table/index.d.mts +7 -3
- package/dist/table/index.d.ts +7 -3
- package/dist/table/index.js +233 -111
- package/dist/table/index.mjs +230 -116
- package/dist/table/item_loader.d.mts +5 -4
- package/dist/table/item_loader.d.ts +5 -4
- package/dist/table/load_table.d.mts +36 -0
- package/dist/table/load_table.d.ts +36 -0
- package/dist/table/load_table.js +87 -0
- package/dist/table/load_table.mjs +66 -0
- package/dist/table/loader.d.mts +10 -15
- package/dist/table/loader.d.ts +10 -15
- package/dist/table/loader.js +67 -31
- package/dist/table/loader.mjs +67 -32
- package/dist/table/page.d.mts +6 -16
- package/dist/table/page.d.ts +6 -16
- package/dist/table/page.js +247 -169
- package/dist/table/page.mjs +248 -176
- package/dist/table/repository.d.mts +14 -10
- package/dist/table/repository.d.ts +14 -10
- package/dist/table/repository.js +5 -1
- package/dist/table/repository.mjs +5 -1
- package/dist/table/table.d.mts +4 -1
- package/dist/table/table.d.ts +4 -1
- package/dist/table/table.js +55 -6
- package/dist/table/table.mjs +55 -6
- package/dist/table/table_form.d.mts +13 -0
- package/dist/table/table_form.d.ts +13 -0
- package/dist/table/table_form.js +345 -0
- package/dist/table/table_form.mjs +320 -0
- package/dist/table/use_table.d.mts +4 -0
- package/dist/table/use_table.d.ts +4 -0
- package/dist/table/use_table.js +34 -0
- package/dist/table/use_table.mjs +9 -0
- package/package.json +2 -2
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InferSelectModel, SQLWrapper } from 'drizzle-orm';
|
|
2
2
|
import { ActionFunctionArgs, LoaderFunctionArgs } from 'react-router';
|
|
3
3
|
import { TableRepository } from '../table/repository.mjs';
|
|
4
|
+
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
4
5
|
import { WithAuthHandler } from '../auth/with_auth.mjs';
|
|
5
|
-
import 'drizzle-orm/
|
|
6
|
+
import 'drizzle-orm/node-postgres';
|
|
6
7
|
import 'dn-react-toolkit/auth';
|
|
7
8
|
import 'dn-react-toolkit/auth/server';
|
|
8
9
|
|
|
9
|
-
type APIHandlerOptions<T extends
|
|
10
|
+
type APIHandlerOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
10
11
|
withAuthAction: WithAuthHandler<ActionFunctionArgs>;
|
|
11
12
|
repository: TableRepository<T, TSelect>;
|
|
12
13
|
validators?: {
|
|
@@ -21,7 +22,7 @@ type APIHandlerOptions<T extends Table, TSelect> = {
|
|
|
21
22
|
injectUserId?: boolean;
|
|
22
23
|
roles?: string[];
|
|
23
24
|
};
|
|
24
|
-
declare function apiHandler<T extends
|
|
25
|
+
declare function apiHandler<T extends PgTableWithColumns<any>, TSelect>({ withAuthAction, repository, validators, existingConditions, injectUserId, roles, }: APIHandlerOptions<T, TSelect>): {
|
|
25
26
|
loader: ({ request }: LoaderFunctionArgs) => Promise<{}>;
|
|
26
27
|
action: (arg: ActionFunctionArgs<any>) => Promise<unknown> | unknown;
|
|
27
28
|
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InferSelectModel, SQLWrapper } from 'drizzle-orm';
|
|
2
2
|
import { ActionFunctionArgs, LoaderFunctionArgs } from 'react-router';
|
|
3
3
|
import { TableRepository } from '../table/repository.js';
|
|
4
|
+
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
4
5
|
import { WithAuthHandler } from '../auth/with_auth.js';
|
|
5
|
-
import 'drizzle-orm/
|
|
6
|
+
import 'drizzle-orm/node-postgres';
|
|
6
7
|
import 'dn-react-toolkit/auth';
|
|
7
8
|
import 'dn-react-toolkit/auth/server';
|
|
8
9
|
|
|
9
|
-
type APIHandlerOptions<T extends
|
|
10
|
+
type APIHandlerOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
10
11
|
withAuthAction: WithAuthHandler<ActionFunctionArgs>;
|
|
11
12
|
repository: TableRepository<T, TSelect>;
|
|
12
13
|
validators?: {
|
|
@@ -21,7 +22,7 @@ type APIHandlerOptions<T extends Table, TSelect> = {
|
|
|
21
22
|
injectUserId?: boolean;
|
|
22
23
|
roles?: string[];
|
|
23
24
|
};
|
|
24
|
-
declare function apiHandler<T extends
|
|
25
|
+
declare function apiHandler<T extends PgTableWithColumns<any>, TSelect>({ withAuthAction, repository, validators, existingConditions, injectUserId, roles, }: APIHandlerOptions<T, TSelect>): {
|
|
25
26
|
loader: ({ request }: LoaderFunctionArgs) => Promise<{}>;
|
|
26
27
|
action: (arg: ActionFunctionArgs<any>) => Promise<unknown> | unknown;
|
|
27
28
|
};
|
|
@@ -25,7 +25,6 @@ __export(create_api_handler_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(create_api_handler_exports);
|
|
26
26
|
var import_http = require("dn-react-toolkit/http");
|
|
27
27
|
var import_drizzle_orm = require("drizzle-orm");
|
|
28
|
-
var import_react_router = require("react-router");
|
|
29
28
|
var import_uuid = require("uuid");
|
|
30
29
|
|
|
31
30
|
// src/crud/serialize.ts
|
package/dist/api/index.d.mts
CHANGED
|
@@ -6,6 +6,7 @@ import 'dn-react-toolkit/auth/server';
|
|
|
6
6
|
import 'dn-react-toolkit/file/server';
|
|
7
7
|
import 'drizzle-orm';
|
|
8
8
|
import '../table/repository.mjs';
|
|
9
|
+
import 'drizzle-orm/node-postgres';
|
|
9
10
|
import 'drizzle-orm/pg-core';
|
|
10
11
|
import '../auth/with_auth.mjs';
|
|
11
12
|
import 'dn-react-toolkit/auth';
|
package/dist/api/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import 'dn-react-toolkit/auth/server';
|
|
|
6
6
|
import 'dn-react-toolkit/file/server';
|
|
7
7
|
import 'drizzle-orm';
|
|
8
8
|
import '../table/repository.js';
|
|
9
|
+
import 'drizzle-orm/node-postgres';
|
|
9
10
|
import 'drizzle-orm/pg-core';
|
|
10
11
|
import '../auth/with_auth.js';
|
|
11
12
|
import 'dn-react-toolkit/auth';
|
package/dist/api/index.js
CHANGED
|
@@ -250,7 +250,6 @@ var createAPIHandler = ({
|
|
|
250
250
|
// src/api/create_api_handler.ts
|
|
251
251
|
var import_http2 = require("dn-react-toolkit/http");
|
|
252
252
|
var import_drizzle_orm = require("drizzle-orm");
|
|
253
|
-
var import_react_router2 = require("react-router");
|
|
254
253
|
var import_uuid = require("uuid");
|
|
255
254
|
|
|
256
255
|
// src/crud/serialize.ts
|
|
@@ -378,21 +377,29 @@ function apiHandler({
|
|
|
378
377
|
|
|
379
378
|
// src/api/item_api_handler.ts
|
|
380
379
|
var import_http3 = require("dn-react-toolkit/http");
|
|
381
|
-
var import_react_router3 = require("react-router");
|
|
382
380
|
function itemApiHandler({
|
|
383
381
|
withAuthAction,
|
|
384
|
-
repository
|
|
382
|
+
repository,
|
|
383
|
+
isOwnedBy,
|
|
384
|
+
roles
|
|
385
385
|
}) {
|
|
386
386
|
const loader = async ({ request }) => {
|
|
387
387
|
return {};
|
|
388
388
|
};
|
|
389
389
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
390
|
-
if (!auth || auth.role
|
|
391
|
-
|
|
390
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
391
|
+
throw (0, import_http3.UNAUTHORIZED)();
|
|
392
|
+
}
|
|
393
|
+
const itemId = params.itemId;
|
|
394
|
+
const existing = await repository.find(itemId);
|
|
395
|
+
if (!existing) {
|
|
396
|
+
throw (0, import_http3.NOT_FOUND)();
|
|
397
|
+
}
|
|
398
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
399
|
+
throw (0, import_http3.FORBIDDEN)();
|
|
392
400
|
}
|
|
393
401
|
switch (request.method) {
|
|
394
402
|
case "DELETE": {
|
|
395
|
-
const itemId = params.itemId;
|
|
396
403
|
await repository.delete(itemId);
|
|
397
404
|
return {};
|
|
398
405
|
}
|
package/dist/api/index.mjs
CHANGED
|
@@ -245,7 +245,6 @@ import {
|
|
|
245
245
|
import {
|
|
246
246
|
and
|
|
247
247
|
} from "drizzle-orm";
|
|
248
|
-
import "react-router";
|
|
249
248
|
import { v4 } from "uuid";
|
|
250
249
|
|
|
251
250
|
// src/crud/serialize.ts
|
|
@@ -372,22 +371,30 @@ function apiHandler({
|
|
|
372
371
|
}
|
|
373
372
|
|
|
374
373
|
// src/api/item_api_handler.ts
|
|
375
|
-
import { UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
|
|
376
|
-
import "react-router";
|
|
374
|
+
import { FORBIDDEN, NOT_FOUND as NOT_FOUND2, UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
|
|
377
375
|
function itemApiHandler({
|
|
378
376
|
withAuthAction,
|
|
379
|
-
repository
|
|
377
|
+
repository,
|
|
378
|
+
isOwnedBy,
|
|
379
|
+
roles
|
|
380
380
|
}) {
|
|
381
381
|
const loader = async ({ request }) => {
|
|
382
382
|
return {};
|
|
383
383
|
};
|
|
384
384
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
385
|
-
if (!auth || auth.role
|
|
386
|
-
|
|
385
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
386
|
+
throw UNAUTHORIZED2();
|
|
387
|
+
}
|
|
388
|
+
const itemId = params.itemId;
|
|
389
|
+
const existing = await repository.find(itemId);
|
|
390
|
+
if (!existing) {
|
|
391
|
+
throw NOT_FOUND2();
|
|
392
|
+
}
|
|
393
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
394
|
+
throw FORBIDDEN();
|
|
387
395
|
}
|
|
388
396
|
switch (request.method) {
|
|
389
397
|
case "DELETE": {
|
|
390
|
-
const itemId = params.itemId;
|
|
391
398
|
await repository.delete(itemId);
|
|
392
399
|
return {};
|
|
393
400
|
}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import { Table } from 'drizzle-orm';
|
|
2
1
|
import { LoaderFunctionArgs } from 'react-router';
|
|
3
2
|
import { TableRepository } from '../table/repository.mjs';
|
|
3
|
+
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
4
4
|
import { WithAuthHandler } from '../auth/with_auth.mjs';
|
|
5
|
-
import '
|
|
6
|
-
import '
|
|
5
|
+
import { AccessTokenPayload } from 'dn-react-toolkit/auth';
|
|
6
|
+
import 'drizzle-orm';
|
|
7
|
+
import 'drizzle-orm/node-postgres';
|
|
7
8
|
import 'dn-react-toolkit/auth/server';
|
|
8
9
|
|
|
9
|
-
type ItemAPIHandlerOptions<T extends
|
|
10
|
+
type ItemAPIHandlerOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
10
11
|
withAuthAction: WithAuthHandler<LoaderFunctionArgs>;
|
|
11
12
|
repository: TableRepository<T, TSelect>;
|
|
13
|
+
isOwnedBy?: (item: TSelect, auth: AccessTokenPayload | undefined) => boolean;
|
|
14
|
+
roles?: string[];
|
|
12
15
|
};
|
|
13
|
-
declare function itemApiHandler<T extends
|
|
16
|
+
declare function itemApiHandler<T extends PgTableWithColumns<any>, TSelect>({ withAuthAction, repository, isOwnedBy, roles, }: ItemAPIHandlerOptions<T, TSelect>): {
|
|
14
17
|
loader: ({ request }: LoaderFunctionArgs) => Promise<{}>;
|
|
15
18
|
action: (arg: LoaderFunctionArgs<any>) => Promise<unknown> | unknown;
|
|
16
19
|
};
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import { Table } from 'drizzle-orm';
|
|
2
1
|
import { LoaderFunctionArgs } from 'react-router';
|
|
3
2
|
import { TableRepository } from '../table/repository.js';
|
|
3
|
+
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
4
4
|
import { WithAuthHandler } from '../auth/with_auth.js';
|
|
5
|
-
import '
|
|
6
|
-
import '
|
|
5
|
+
import { AccessTokenPayload } from 'dn-react-toolkit/auth';
|
|
6
|
+
import 'drizzle-orm';
|
|
7
|
+
import 'drizzle-orm/node-postgres';
|
|
7
8
|
import 'dn-react-toolkit/auth/server';
|
|
8
9
|
|
|
9
|
-
type ItemAPIHandlerOptions<T extends
|
|
10
|
+
type ItemAPIHandlerOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
10
11
|
withAuthAction: WithAuthHandler<LoaderFunctionArgs>;
|
|
11
12
|
repository: TableRepository<T, TSelect>;
|
|
13
|
+
isOwnedBy?: (item: TSelect, auth: AccessTokenPayload | undefined) => boolean;
|
|
14
|
+
roles?: string[];
|
|
12
15
|
};
|
|
13
|
-
declare function itemApiHandler<T extends
|
|
16
|
+
declare function itemApiHandler<T extends PgTableWithColumns<any>, TSelect>({ withAuthAction, repository, isOwnedBy, roles, }: ItemAPIHandlerOptions<T, TSelect>): {
|
|
14
17
|
loader: ({ request }: LoaderFunctionArgs) => Promise<{}>;
|
|
15
18
|
action: (arg: LoaderFunctionArgs<any>) => Promise<unknown> | unknown;
|
|
16
19
|
};
|
|
@@ -24,21 +24,29 @@ __export(item_api_handler_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(item_api_handler_exports);
|
|
26
26
|
var import_http = require("dn-react-toolkit/http");
|
|
27
|
-
var import_react_router = require("react-router");
|
|
28
27
|
function itemApiHandler({
|
|
29
28
|
withAuthAction,
|
|
30
|
-
repository
|
|
29
|
+
repository,
|
|
30
|
+
isOwnedBy,
|
|
31
|
+
roles
|
|
31
32
|
}) {
|
|
32
33
|
const loader = async ({ request }) => {
|
|
33
34
|
return {};
|
|
34
35
|
};
|
|
35
36
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
36
|
-
if (!auth || auth.role
|
|
37
|
-
|
|
37
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
38
|
+
throw (0, import_http.UNAUTHORIZED)();
|
|
39
|
+
}
|
|
40
|
+
const itemId = params.itemId;
|
|
41
|
+
const existing = await repository.find(itemId);
|
|
42
|
+
if (!existing) {
|
|
43
|
+
throw (0, import_http.NOT_FOUND)();
|
|
44
|
+
}
|
|
45
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
46
|
+
throw (0, import_http.FORBIDDEN)();
|
|
38
47
|
}
|
|
39
48
|
switch (request.method) {
|
|
40
49
|
case "DELETE": {
|
|
41
|
-
const itemId = params.itemId;
|
|
42
50
|
await repository.delete(itemId);
|
|
43
51
|
return {};
|
|
44
52
|
}
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
// src/api/item_api_handler.ts
|
|
2
|
-
import { UNAUTHORIZED } from "dn-react-toolkit/http";
|
|
3
|
-
import "react-router";
|
|
2
|
+
import { FORBIDDEN, NOT_FOUND, UNAUTHORIZED } from "dn-react-toolkit/http";
|
|
4
3
|
function itemApiHandler({
|
|
5
4
|
withAuthAction,
|
|
6
|
-
repository
|
|
5
|
+
repository,
|
|
6
|
+
isOwnedBy,
|
|
7
|
+
roles
|
|
7
8
|
}) {
|
|
8
9
|
const loader = async ({ request }) => {
|
|
9
10
|
return {};
|
|
10
11
|
};
|
|
11
12
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
12
|
-
if (!auth || auth.role
|
|
13
|
-
|
|
13
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
14
|
+
throw UNAUTHORIZED();
|
|
15
|
+
}
|
|
16
|
+
const itemId = params.itemId;
|
|
17
|
+
const existing = await repository.find(itemId);
|
|
18
|
+
if (!existing) {
|
|
19
|
+
throw NOT_FOUND();
|
|
20
|
+
}
|
|
21
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
22
|
+
throw FORBIDDEN();
|
|
14
23
|
}
|
|
15
24
|
switch (request.method) {
|
|
16
25
|
case "DELETE": {
|
|
17
|
-
const itemId = params.itemId;
|
|
18
26
|
await repository.delete(itemId);
|
|
19
27
|
return {};
|
|
20
28
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { LoaderFunctionArgs, LoaderFunction } from 'react-router';
|
|
2
|
-
import { TableLoaderOptions } from '../table/loader.mjs';
|
|
3
2
|
import { TableItemLoaderOptions } from '../table/item_loader.mjs';
|
|
4
|
-
import { Table } from 'drizzle-orm';
|
|
5
3
|
import { TableRepository } from '../table/repository.mjs';
|
|
4
|
+
import { TableLoaderOptions } from '../table/load_table.mjs';
|
|
5
|
+
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
6
6
|
import { APIHandlerOptions } from '../api/create_api_handler.mjs';
|
|
7
|
-
import 'drizzle-orm
|
|
7
|
+
import 'drizzle-orm';
|
|
8
|
+
import 'drizzle-orm/node-postgres';
|
|
8
9
|
import '../auth/with_auth.mjs';
|
|
9
10
|
import 'dn-react-toolkit/auth';
|
|
10
11
|
import 'dn-react-toolkit/auth/server';
|
|
11
12
|
|
|
12
|
-
type CrudHandlerOptions<T extends
|
|
13
|
+
type CrudHandlerOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
13
14
|
repository: TableRepository<T, TSelect>;
|
|
14
15
|
apiHandlerOptions: Omit<APIHandlerOptions<T, TSelect>, "repository">;
|
|
15
16
|
loaderOptions: Omit<TableLoaderOptions<T, TSelect>, "repository"> & {
|
|
@@ -20,6 +21,6 @@ type CrudHandlerOptions<T extends Table, TSelect> = {
|
|
|
20
21
|
};
|
|
21
22
|
};
|
|
22
23
|
type CrudHandler = (prefix: string) => (args: LoaderFunctionArgs) => Promise<any>;
|
|
23
|
-
declare function crudHandler<T extends
|
|
24
|
+
declare function crudHandler<T extends PgTableWithColumns<any>, TSelect>({ repository, apiHandlerOptions, loaderOptions, itemLoaderOptions, }: CrudHandlerOptions<T, TSelect>): (prefix: string) => (args: LoaderFunctionArgs) => Promise<unknown>;
|
|
24
25
|
|
|
25
26
|
export { type CrudHandler, type CrudHandlerOptions, crudHandler };
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { LoaderFunctionArgs, LoaderFunction } from 'react-router';
|
|
2
|
-
import { TableLoaderOptions } from '../table/loader.js';
|
|
3
2
|
import { TableItemLoaderOptions } from '../table/item_loader.js';
|
|
4
|
-
import { Table } from 'drizzle-orm';
|
|
5
3
|
import { TableRepository } from '../table/repository.js';
|
|
4
|
+
import { TableLoaderOptions } from '../table/load_table.js';
|
|
5
|
+
import { PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
6
6
|
import { APIHandlerOptions } from '../api/create_api_handler.js';
|
|
7
|
-
import 'drizzle-orm
|
|
7
|
+
import 'drizzle-orm';
|
|
8
|
+
import 'drizzle-orm/node-postgres';
|
|
8
9
|
import '../auth/with_auth.js';
|
|
9
10
|
import 'dn-react-toolkit/auth';
|
|
10
11
|
import 'dn-react-toolkit/auth/server';
|
|
11
12
|
|
|
12
|
-
type CrudHandlerOptions<T extends
|
|
13
|
+
type CrudHandlerOptions<T extends PgTableWithColumns<any>, TSelect> = {
|
|
13
14
|
repository: TableRepository<T, TSelect>;
|
|
14
15
|
apiHandlerOptions: Omit<APIHandlerOptions<T, TSelect>, "repository">;
|
|
15
16
|
loaderOptions: Omit<TableLoaderOptions<T, TSelect>, "repository"> & {
|
|
@@ -20,6 +21,6 @@ type CrudHandlerOptions<T extends Table, TSelect> = {
|
|
|
20
21
|
};
|
|
21
22
|
};
|
|
22
23
|
type CrudHandler = (prefix: string) => (args: LoaderFunctionArgs) => Promise<any>;
|
|
23
|
-
declare function crudHandler<T extends
|
|
24
|
+
declare function crudHandler<T extends PgTableWithColumns<any>, TSelect>({ repository, apiHandlerOptions, loaderOptions, itemLoaderOptions, }: CrudHandlerOptions<T, TSelect>): (prefix: string) => (args: LoaderFunctionArgs) => Promise<unknown>;
|
|
24
25
|
|
|
25
26
|
export { type CrudHandler, type CrudHandlerOptions, crudHandler };
|
package/dist/crud/crud_loader.js
CHANGED
|
@@ -24,45 +24,79 @@ __export(crud_loader_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(crud_loader_exports);
|
|
26
26
|
|
|
27
|
-
// src/table/
|
|
27
|
+
// src/table/load_table.tsx
|
|
28
28
|
var import_drizzle_orm = require("drizzle-orm");
|
|
29
|
+
async function loadTable({
|
|
30
|
+
request,
|
|
31
|
+
repository,
|
|
32
|
+
options
|
|
33
|
+
}) {
|
|
34
|
+
const searchParams = new URL(request.url).searchParams;
|
|
35
|
+
const { where, searchKey, defaultOrderBy, defaultDirection } = options;
|
|
36
|
+
const query = searchParams.get("query") ?? void 0;
|
|
37
|
+
const limit = Number(searchParams.get("limit") ?? "20");
|
|
38
|
+
const offset = Number(searchParams.get("offset") ?? "0");
|
|
39
|
+
const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
|
|
40
|
+
const direction = searchParams.get("direction") ?? defaultDirection;
|
|
41
|
+
const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
|
|
42
|
+
const param = searchParams.get(key);
|
|
43
|
+
if (param) {
|
|
44
|
+
return (0, import_drizzle_orm.eq)(
|
|
45
|
+
repository.schema[key],
|
|
46
|
+
decodeURIComponent(param)
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return void 0;
|
|
50
|
+
}).filter(Boolean);
|
|
51
|
+
const whereClauses = (0, import_drizzle_orm.and)(
|
|
52
|
+
searchKey && query ? (0, import_drizzle_orm.ilike)(
|
|
53
|
+
repository.schema[searchKey],
|
|
54
|
+
`%${query}%`
|
|
55
|
+
) : void 0,
|
|
56
|
+
...filterWhere,
|
|
57
|
+
...where ?? []
|
|
58
|
+
);
|
|
59
|
+
const total = await repository.countTotal({ where: whereClauses });
|
|
60
|
+
const items = await repository.findAll({
|
|
61
|
+
orderBy,
|
|
62
|
+
direction,
|
|
63
|
+
limit,
|
|
64
|
+
offset,
|
|
65
|
+
where: whereClauses
|
|
66
|
+
});
|
|
67
|
+
const filters = Object.fromEntries(
|
|
68
|
+
await Promise.all(
|
|
69
|
+
Object.keys(options.filters ?? {}).map(async (key) => {
|
|
70
|
+
const values = await repository.select(key);
|
|
71
|
+
return [key, values.filter(Boolean)];
|
|
72
|
+
})
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
return {
|
|
76
|
+
items,
|
|
77
|
+
total,
|
|
78
|
+
limit,
|
|
79
|
+
offset,
|
|
80
|
+
orderBy,
|
|
81
|
+
direction,
|
|
82
|
+
searchKey,
|
|
83
|
+
filters
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/table/loader.tsx
|
|
29
88
|
function tableLoader({
|
|
30
89
|
repository,
|
|
31
|
-
|
|
90
|
+
options
|
|
32
91
|
}) {
|
|
33
92
|
return async ({ request }) => {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const offset = Number(searchParams.get("offset") ?? "0");
|
|
39
|
-
const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
|
|
40
|
-
const direction = searchParams.get("direction") ?? defaultDirection;
|
|
41
|
-
const whereClauses = (0, import_drizzle_orm.and)(
|
|
42
|
-
searchKey && query ? (0, import_drizzle_orm.ilike)(
|
|
43
|
-
repository.schema[searchKey],
|
|
44
|
-
`%${query}%`
|
|
45
|
-
) : void 0,
|
|
46
|
-
...where ?? []
|
|
47
|
-
);
|
|
48
|
-
const total = await repository.countTotal({ where: whereClauses });
|
|
49
|
-
const items = await repository.findAll({
|
|
50
|
-
orderBy,
|
|
51
|
-
direction,
|
|
52
|
-
limit,
|
|
53
|
-
offset,
|
|
54
|
-
where: whereClauses
|
|
93
|
+
const table = await loadTable({
|
|
94
|
+
request,
|
|
95
|
+
repository,
|
|
96
|
+
options
|
|
55
97
|
});
|
|
56
98
|
return {
|
|
57
|
-
table
|
|
58
|
-
items,
|
|
59
|
-
total,
|
|
60
|
-
limit,
|
|
61
|
-
offset,
|
|
62
|
-
orderBy,
|
|
63
|
-
direction,
|
|
64
|
-
searchKey
|
|
65
|
-
}
|
|
99
|
+
table
|
|
66
100
|
};
|
|
67
101
|
};
|
|
68
102
|
}
|
|
@@ -86,7 +120,6 @@ var tableItemloader = ({
|
|
|
86
120
|
// src/api/create_api_handler.ts
|
|
87
121
|
var import_http = require("dn-react-toolkit/http");
|
|
88
122
|
var import_drizzle_orm2 = require("drizzle-orm");
|
|
89
|
-
var import_react_router = require("react-router");
|
|
90
123
|
var import_uuid = require("uuid");
|
|
91
124
|
|
|
92
125
|
// src/crud/serialize.ts
|
|
@@ -214,21 +247,29 @@ function apiHandler({
|
|
|
214
247
|
|
|
215
248
|
// src/api/item_api_handler.ts
|
|
216
249
|
var import_http2 = require("dn-react-toolkit/http");
|
|
217
|
-
var import_react_router2 = require("react-router");
|
|
218
250
|
function itemApiHandler({
|
|
219
251
|
withAuthAction,
|
|
220
|
-
repository
|
|
252
|
+
repository,
|
|
253
|
+
isOwnedBy,
|
|
254
|
+
roles
|
|
221
255
|
}) {
|
|
222
256
|
const loader = async ({ request }) => {
|
|
223
257
|
return {};
|
|
224
258
|
};
|
|
225
259
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
226
|
-
if (!auth || auth.role
|
|
227
|
-
|
|
260
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
261
|
+
throw (0, import_http2.UNAUTHORIZED)();
|
|
262
|
+
}
|
|
263
|
+
const itemId = params.itemId;
|
|
264
|
+
const existing = await repository.find(itemId);
|
|
265
|
+
if (!existing) {
|
|
266
|
+
throw (0, import_http2.NOT_FOUND)();
|
|
267
|
+
}
|
|
268
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
269
|
+
throw (0, import_http2.FORBIDDEN)();
|
|
228
270
|
}
|
|
229
271
|
switch (request.method) {
|
|
230
272
|
case "DELETE": {
|
|
231
|
-
const itemId = params.itemId;
|
|
232
273
|
await repository.delete(itemId);
|
|
233
274
|
return {};
|
|
234
275
|
}
|
|
@@ -1,45 +1,80 @@
|
|
|
1
|
-
// src/table/
|
|
1
|
+
// src/table/load_table.tsx
|
|
2
2
|
import {
|
|
3
3
|
and,
|
|
4
|
+
eq,
|
|
4
5
|
ilike
|
|
5
6
|
} from "drizzle-orm";
|
|
7
|
+
async function loadTable({
|
|
8
|
+
request,
|
|
9
|
+
repository,
|
|
10
|
+
options
|
|
11
|
+
}) {
|
|
12
|
+
const searchParams = new URL(request.url).searchParams;
|
|
13
|
+
const { where, searchKey, defaultOrderBy, defaultDirection } = options;
|
|
14
|
+
const query = searchParams.get("query") ?? void 0;
|
|
15
|
+
const limit = Number(searchParams.get("limit") ?? "20");
|
|
16
|
+
const offset = Number(searchParams.get("offset") ?? "0");
|
|
17
|
+
const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
|
|
18
|
+
const direction = searchParams.get("direction") ?? defaultDirection;
|
|
19
|
+
const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
|
|
20
|
+
const param = searchParams.get(key);
|
|
21
|
+
if (param) {
|
|
22
|
+
return eq(
|
|
23
|
+
repository.schema[key],
|
|
24
|
+
decodeURIComponent(param)
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
return void 0;
|
|
28
|
+
}).filter(Boolean);
|
|
29
|
+
const whereClauses = and(
|
|
30
|
+
searchKey && query ? ilike(
|
|
31
|
+
repository.schema[searchKey],
|
|
32
|
+
`%${query}%`
|
|
33
|
+
) : void 0,
|
|
34
|
+
...filterWhere,
|
|
35
|
+
...where ?? []
|
|
36
|
+
);
|
|
37
|
+
const total = await repository.countTotal({ where: whereClauses });
|
|
38
|
+
const items = await repository.findAll({
|
|
39
|
+
orderBy,
|
|
40
|
+
direction,
|
|
41
|
+
limit,
|
|
42
|
+
offset,
|
|
43
|
+
where: whereClauses
|
|
44
|
+
});
|
|
45
|
+
const filters = Object.fromEntries(
|
|
46
|
+
await Promise.all(
|
|
47
|
+
Object.keys(options.filters ?? {}).map(async (key) => {
|
|
48
|
+
const values = await repository.select(key);
|
|
49
|
+
return [key, values.filter(Boolean)];
|
|
50
|
+
})
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
return {
|
|
54
|
+
items,
|
|
55
|
+
total,
|
|
56
|
+
limit,
|
|
57
|
+
offset,
|
|
58
|
+
orderBy,
|
|
59
|
+
direction,
|
|
60
|
+
searchKey,
|
|
61
|
+
filters
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/table/loader.tsx
|
|
6
66
|
function tableLoader({
|
|
7
67
|
repository,
|
|
8
|
-
|
|
68
|
+
options
|
|
9
69
|
}) {
|
|
10
70
|
return async ({ request }) => {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const offset = Number(searchParams.get("offset") ?? "0");
|
|
16
|
-
const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
|
|
17
|
-
const direction = searchParams.get("direction") ?? defaultDirection;
|
|
18
|
-
const whereClauses = and(
|
|
19
|
-
searchKey && query ? ilike(
|
|
20
|
-
repository.schema[searchKey],
|
|
21
|
-
`%${query}%`
|
|
22
|
-
) : void 0,
|
|
23
|
-
...where ?? []
|
|
24
|
-
);
|
|
25
|
-
const total = await repository.countTotal({ where: whereClauses });
|
|
26
|
-
const items = await repository.findAll({
|
|
27
|
-
orderBy,
|
|
28
|
-
direction,
|
|
29
|
-
limit,
|
|
30
|
-
offset,
|
|
31
|
-
where: whereClauses
|
|
71
|
+
const table = await loadTable({
|
|
72
|
+
request,
|
|
73
|
+
repository,
|
|
74
|
+
options
|
|
32
75
|
});
|
|
33
76
|
return {
|
|
34
|
-
table
|
|
35
|
-
items,
|
|
36
|
-
total,
|
|
37
|
-
limit,
|
|
38
|
-
offset,
|
|
39
|
-
orderBy,
|
|
40
|
-
direction,
|
|
41
|
-
searchKey
|
|
42
|
-
}
|
|
77
|
+
table
|
|
43
78
|
};
|
|
44
79
|
};
|
|
45
80
|
}
|
|
@@ -72,7 +107,6 @@ import {
|
|
|
72
107
|
import {
|
|
73
108
|
and as and2
|
|
74
109
|
} from "drizzle-orm";
|
|
75
|
-
import "react-router";
|
|
76
110
|
import { v4 } from "uuid";
|
|
77
111
|
|
|
78
112
|
// src/crud/serialize.ts
|
|
@@ -199,22 +233,30 @@ function apiHandler({
|
|
|
199
233
|
}
|
|
200
234
|
|
|
201
235
|
// src/api/item_api_handler.ts
|
|
202
|
-
import { UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
|
|
203
|
-
import "react-router";
|
|
236
|
+
import { FORBIDDEN, NOT_FOUND, UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
|
|
204
237
|
function itemApiHandler({
|
|
205
238
|
withAuthAction,
|
|
206
|
-
repository
|
|
239
|
+
repository,
|
|
240
|
+
isOwnedBy,
|
|
241
|
+
roles
|
|
207
242
|
}) {
|
|
208
243
|
const loader = async ({ request }) => {
|
|
209
244
|
return {};
|
|
210
245
|
};
|
|
211
246
|
const action = withAuthAction((auth) => async ({ params, request }) => {
|
|
212
|
-
if (!auth || auth.role
|
|
213
|
-
|
|
247
|
+
if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
|
|
248
|
+
throw UNAUTHORIZED2();
|
|
249
|
+
}
|
|
250
|
+
const itemId = params.itemId;
|
|
251
|
+
const existing = await repository.find(itemId);
|
|
252
|
+
if (!existing) {
|
|
253
|
+
throw NOT_FOUND();
|
|
254
|
+
}
|
|
255
|
+
if (isOwnedBy && !isOwnedBy(existing, auth)) {
|
|
256
|
+
throw FORBIDDEN();
|
|
214
257
|
}
|
|
215
258
|
switch (request.method) {
|
|
216
259
|
case "DELETE": {
|
|
217
|
-
const itemId = params.itemId;
|
|
218
260
|
await repository.delete(itemId);
|
|
219
261
|
return {};
|
|
220
262
|
}
|