@naisys/erp 3.0.0-beta.9 → 3.0.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/.env.example +5 -0
- package/client-dist/assets/index-CSiMTJfw.css +14 -0
- package/client-dist/assets/index-D5R6NBeW.js +11177 -0
- package/client-dist/assets/rolldown-runtime-B-1-B7_t.js +33 -0
- package/client-dist/assets/vendor-CbiEATh3.js +73851 -0
- package/client-dist/assets/vendor-D8d_HnwE.css +9604 -0
- package/client-dist/favicon-16x16.png +0 -0
- package/client-dist/favicon-32x32.png +0 -0
- package/client-dist/favicon.ico +0 -0
- package/client-dist/index.html +17 -2
- package/dist/{dbConfig.js → database/dbConfig.js} +1 -1
- package/dist/{erpDb.js → database/erpDb.js} +1 -1
- package/dist/erpRoutes.js +115 -0
- package/dist/erpServer.js +92 -162
- package/dist/error-handler.js +3 -0
- package/dist/generated/prisma/internal/class.js +6 -6
- package/dist/generated/prisma/internal/prismaNamespace.js +7 -5
- package/dist/middleware/auth-middleware.js +146 -0
- package/dist/route-helpers.js +2 -2
- package/dist/routes/admin.js +15 -7
- package/dist/routes/audit.js +1 -1
- package/dist/routes/{item-fields.js → items/item-fields.js} +24 -22
- package/dist/routes/{item-instances.js → items/item-instances.js} +42 -24
- package/dist/routes/{items.js → items/items.js} +35 -33
- package/dist/routes/{operation-dependencies.js → operations/operation-dependencies.js} +6 -6
- package/dist/routes/{operation-field-refs.js → operations/operation-field-refs.js} +6 -6
- package/dist/routes/{operation-run-comments.js → operations/operation-run-comments.js} +5 -5
- package/dist/routes/{operation-run-transitions.js → operations/operation-run-transitions.js} +29 -13
- package/dist/routes/{operation-runs.js → operations/operation-runs.js} +48 -10
- package/dist/routes/{operations.js → operations/operations.js} +6 -6
- package/dist/routes/{order-revision-transitions.js → orders/order-revision-transitions.js} +4 -4
- package/dist/routes/{order-revisions.js → orders/order-revisions.js} +6 -6
- package/dist/routes/{order-run-transitions.js → orders/order-run-transitions.js} +11 -5
- package/dist/routes/{order-runs.js → orders/order-runs.js} +7 -5
- package/dist/routes/{orders.js → orders/orders.js} +15 -11
- package/dist/routes/{dispatch.js → production/dispatch.js} +88 -7
- package/dist/routes/{inventory.js → production/inventory.js} +33 -10
- package/dist/routes/{labor-tickets.js → production/labor-tickets.js} +7 -7
- package/dist/routes/{work-centers.js → production/work-centers.js} +29 -29
- package/dist/routes/root.js +1 -1
- package/dist/routes/{step-field-attachments.js → steps/step-field-attachments.js} +8 -8
- package/dist/routes/{step-fields.js → steps/step-fields.js} +6 -6
- package/dist/routes/{step-run-fields.js → steps/step-run-fields.js} +9 -9
- package/dist/routes/{step-run-transitions.js → steps/step-run-transitions.js} +6 -6
- package/dist/routes/{step-runs.js → steps/step-runs.js} +7 -7
- package/dist/routes/{steps.js → steps/steps.js} +5 -5
- package/dist/routes/{auth.js → users/auth.js} +11 -23
- package/dist/routes/{user-permissions.js → users/user-permissions.js} +21 -7
- package/dist/routes/{users.js → users/users.js} +42 -20
- package/dist/services/attachment-service.js +2 -2
- package/dist/services/{item-instance-service.js → inventory/item-instance-service.js} +2 -2
- package/dist/services/{item-service.js → inventory/item-service.js} +2 -2
- package/dist/services/{operation-dependency-service.js → operations/operation-dependency-service.js} +1 -1
- package/dist/services/{operation-run-comment-service.js → operations/operation-run-comment-service.js} +1 -1
- package/dist/services/{operation-run-service.js → operations/operation-run-service.js} +15 -4
- package/dist/services/{operation-service.js → operations/operation-service.js} +2 -2
- package/dist/services/{step-run-service.js → operations/step-run-service.js} +1 -1
- package/dist/services/{step-service.js → operations/step-service.js} +2 -2
- package/dist/services/{order-revision-service.js → orders/order-revision-service.js} +4 -5
- package/dist/services/{order-run-service.js → orders/order-run-service.js} +68 -22
- package/dist/services/{order-service.js → orders/order-service.js} +11 -2
- package/dist/services/{revision-diff-service.js → orders/revision-diff-service.js} +11 -10
- package/dist/services/{field-ref-service.js → production/field-ref-service.js} +1 -1
- package/dist/services/{field-service.js → production/field-service.js} +2 -2
- package/dist/services/{field-value-service.js → production/field-value-service.js} +27 -3
- package/dist/services/production/labor-ticket-backfill.js +67 -0
- package/dist/services/{labor-ticket-service.js → production/labor-ticket-service.js} +21 -15
- package/dist/services/{work-center-service.js → production/work-center-service.js} +2 -2
- package/dist/services/user-service.js +94 -28
- package/dist/version.js +12 -0
- package/npm-shrinkwrap.json +2941 -0
- package/package.json +26 -24
- package/prisma/migrations/20260427010000_hash_user_api_keys/migration.sql +10 -0
- package/prisma/migrations/20260427020000_nullable_user_password_hash/migration.sql +39 -0
- package/prisma/migrations/20260517000000_add_op_run_tokens/migration.sql +2 -0
- package/prisma/schema.prisma +4 -2
- package/client-dist/assets/index-45dVo30p.css +0 -1
- package/client-dist/assets/index-C9uuPHLH.js +0 -168
- package/dist/auth-middleware.js +0 -203
- package/dist/userService.js +0 -118
- /package/bin/{naisys-erp → naisys-erp.js} +0 -0
- /package/dist/{supervisorAuth.js → middleware/supervisorAuth.js} +0 -0
- /package/dist/{audit.js → services/audit.js} +0 -0
|
Binary file
|
|
Binary file
|
package/client-dist/favicon.ico
CHANGED
|
Binary file
|
package/client-dist/index.html
CHANGED
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
|
|
6
6
|
<link rel="icon" type="image/x-icon" href="/erp/favicon.ico" />
|
|
7
|
+
<link
|
|
8
|
+
rel="icon"
|
|
9
|
+
type="image/png"
|
|
10
|
+
sizes="32x32"
|
|
11
|
+
href="/erp/favicon-32x32.png"
|
|
12
|
+
/>
|
|
13
|
+
<link
|
|
14
|
+
rel="icon"
|
|
15
|
+
type="image/png"
|
|
16
|
+
sizes="16x16"
|
|
17
|
+
href="/erp/favicon-16x16.png"
|
|
18
|
+
/>
|
|
7
19
|
<link
|
|
8
20
|
rel="apple-touch-icon"
|
|
9
21
|
sizes="180x180"
|
|
@@ -33,8 +45,11 @@
|
|
|
33
45
|
<meta name="format-detection" content="telephone=no" />
|
|
34
46
|
|
|
35
47
|
<title>NAISYS ERP</title>
|
|
36
|
-
<script type="module" crossorigin src="/erp/assets/index-
|
|
37
|
-
<link rel="
|
|
48
|
+
<script type="module" crossorigin src="/erp/assets/index-D5R6NBeW.js"></script>
|
|
49
|
+
<link rel="modulepreload" crossorigin href="/erp/assets/rolldown-runtime-B-1-B7_t.js">
|
|
50
|
+
<link rel="modulepreload" crossorigin href="/erp/assets/vendor-CbiEATh3.js">
|
|
51
|
+
<link rel="stylesheet" crossorigin href="/erp/assets/vendor-D8d_HnwE.css">
|
|
52
|
+
<link rel="stylesheet" crossorigin href="/erp/assets/index-CSiMTJfw.css">
|
|
38
53
|
</head>
|
|
39
54
|
<body>
|
|
40
55
|
<div id="root"></div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
|
|
2
|
+
import { PrismaClient } from "../generated/prisma/client.js";
|
|
2
3
|
import { erpDbUrl } from "./dbConfig.js";
|
|
3
|
-
import { PrismaClient } from "./generated/prisma/client.js";
|
|
4
4
|
let _db;
|
|
5
5
|
/**
|
|
6
6
|
* Initialize the ERP database connection and run SQLite pragmas.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { isSupervisorAuth } from "./middleware/supervisorAuth.js";
|
|
2
|
+
import adminRoutes from "./routes/admin.js";
|
|
3
|
+
import auditRoutes from "./routes/audit.js";
|
|
4
|
+
import itemFieldRoutes from "./routes/items/item-fields.js";
|
|
5
|
+
import itemInstanceRoutes from "./routes/items/item-instances.js";
|
|
6
|
+
import itemRoutes from "./routes/items/items.js";
|
|
7
|
+
import operationDependencyRoutes from "./routes/operations/operation-dependencies.js";
|
|
8
|
+
import operationFieldRefRoutes from "./routes/operations/operation-field-refs.js";
|
|
9
|
+
import operationRunCommentRoutes from "./routes/operations/operation-run-comments.js";
|
|
10
|
+
import operationRunTransitionRoutes from "./routes/operations/operation-run-transitions.js";
|
|
11
|
+
import operationRunRoutes from "./routes/operations/operation-runs.js";
|
|
12
|
+
import operationRoutes from "./routes/operations/operations.js";
|
|
13
|
+
import orderRevisionTransitionRoutes from "./routes/orders/order-revision-transitions.js";
|
|
14
|
+
import orderRevisionRoutes from "./routes/orders/order-revisions.js";
|
|
15
|
+
import orderRunTransitionRoutes from "./routes/orders/order-run-transitions.js";
|
|
16
|
+
import orderRunRoutes from "./routes/orders/order-runs.js";
|
|
17
|
+
import orderRoutes from "./routes/orders/orders.js";
|
|
18
|
+
import dispatchRoutes from "./routes/production/dispatch.js";
|
|
19
|
+
import inventoryRoutes from "./routes/production/inventory.js";
|
|
20
|
+
import laborTicketRoutes from "./routes/production/labor-tickets.js";
|
|
21
|
+
import workCenterRoutes from "./routes/production/work-centers.js";
|
|
22
|
+
import rootRoute from "./routes/root.js";
|
|
23
|
+
import schemaRoutes from "./routes/schemas.js";
|
|
24
|
+
import stepFieldAttachmentRoutes from "./routes/steps/step-field-attachments.js";
|
|
25
|
+
import stepFieldRoutes from "./routes/steps/step-fields.js";
|
|
26
|
+
import stepRunFieldRoutes from "./routes/steps/step-run-fields.js";
|
|
27
|
+
import stepRunTransitionRoutes from "./routes/steps/step-run-transitions.js";
|
|
28
|
+
import stepRunRoutes from "./routes/steps/step-runs.js";
|
|
29
|
+
import stepRoutes from "./routes/steps/steps.js";
|
|
30
|
+
import authRoutes from "./routes/users/auth.js";
|
|
31
|
+
import userPermissionRoutes from "./routes/users/user-permissions.js";
|
|
32
|
+
import userRoutes from "./routes/users/users.js";
|
|
33
|
+
export const erpRoutes = (fastify) => {
|
|
34
|
+
fastify.register(adminRoutes, { prefix: "/erp/api/admin" });
|
|
35
|
+
fastify.register(auditRoutes, { prefix: "/erp/api/audit" });
|
|
36
|
+
fastify.register(authRoutes, { prefix: "/erp/api/auth" });
|
|
37
|
+
fastify.register(dispatchRoutes, { prefix: "/erp/api/dispatch" });
|
|
38
|
+
fastify.register(inventoryRoutes, { prefix: "/erp/api/inventory" });
|
|
39
|
+
fastify.register(rootRoute, { prefix: "/erp/api" });
|
|
40
|
+
fastify.register(itemRoutes, { prefix: "/erp/api/items" });
|
|
41
|
+
fastify.register(itemFieldRoutes, {
|
|
42
|
+
prefix: "/erp/api/items/:key/fields",
|
|
43
|
+
});
|
|
44
|
+
fastify.register(itemInstanceRoutes, {
|
|
45
|
+
prefix: "/erp/api/items/:key/instances",
|
|
46
|
+
});
|
|
47
|
+
fastify.register(orderRoutes, {
|
|
48
|
+
prefix: "/erp/api/orders",
|
|
49
|
+
});
|
|
50
|
+
fastify.register(orderRevisionRoutes, {
|
|
51
|
+
prefix: "/erp/api/orders/:orderKey/revs",
|
|
52
|
+
});
|
|
53
|
+
fastify.register(orderRevisionTransitionRoutes, {
|
|
54
|
+
prefix: "/erp/api/orders/:orderKey/revs",
|
|
55
|
+
});
|
|
56
|
+
fastify.register(orderRunRoutes, {
|
|
57
|
+
prefix: "/erp/api/orders/:orderKey/runs",
|
|
58
|
+
});
|
|
59
|
+
fastify.register(orderRunTransitionRoutes, {
|
|
60
|
+
prefix: "/erp/api/orders/:orderKey/runs",
|
|
61
|
+
});
|
|
62
|
+
fastify.register(operationRoutes, {
|
|
63
|
+
prefix: "/erp/api/orders/:orderKey/revs/:revNo/ops",
|
|
64
|
+
});
|
|
65
|
+
fastify.register(operationDependencyRoutes, {
|
|
66
|
+
prefix: "/erp/api/orders/:orderKey/revs/:revNo/ops/:seqNo/deps",
|
|
67
|
+
});
|
|
68
|
+
fastify.register(operationFieldRefRoutes, {
|
|
69
|
+
prefix: "/erp/api/orders/:orderKey/revs/:revNo/ops/:seqNo/field-refs",
|
|
70
|
+
});
|
|
71
|
+
fastify.register(operationRunRoutes, {
|
|
72
|
+
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops",
|
|
73
|
+
});
|
|
74
|
+
fastify.register(operationRunTransitionRoutes, {
|
|
75
|
+
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops",
|
|
76
|
+
});
|
|
77
|
+
fastify.register(laborTicketRoutes, {
|
|
78
|
+
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/labor",
|
|
79
|
+
});
|
|
80
|
+
fastify.register(operationRunCommentRoutes, {
|
|
81
|
+
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/comments",
|
|
82
|
+
});
|
|
83
|
+
fastify.register(stepRunRoutes, {
|
|
84
|
+
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/steps",
|
|
85
|
+
});
|
|
86
|
+
fastify.register(stepRunTransitionRoutes, {
|
|
87
|
+
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/steps",
|
|
88
|
+
});
|
|
89
|
+
fastify.register(stepRunFieldRoutes, {
|
|
90
|
+
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/steps",
|
|
91
|
+
});
|
|
92
|
+
fastify.register(stepFieldAttachmentRoutes, {
|
|
93
|
+
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/steps/:stepSeqNo/fields/:fieldSeqNo/attachments",
|
|
94
|
+
});
|
|
95
|
+
fastify.register(stepFieldAttachmentRoutes, {
|
|
96
|
+
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/steps/:stepSeqNo/sets/:setIndex/fields/:fieldSeqNo/attachments",
|
|
97
|
+
});
|
|
98
|
+
fastify.register(stepRoutes, {
|
|
99
|
+
prefix: "/erp/api/orders/:orderKey/revs/:revNo/ops/:seqNo/steps",
|
|
100
|
+
});
|
|
101
|
+
fastify.register(stepFieldRoutes, {
|
|
102
|
+
prefix: "/erp/api/orders/:orderKey/revs/:revNo/ops/:seqNo/steps/:stepSeqNo/fields",
|
|
103
|
+
});
|
|
104
|
+
fastify.register(schemaRoutes, { prefix: "/erp/api/schemas" });
|
|
105
|
+
fastify.register(userRoutes, { prefix: "/erp/api/users" });
|
|
106
|
+
fastify.register(userPermissionRoutes, { prefix: "/erp/api/users" });
|
|
107
|
+
fastify.register(workCenterRoutes, { prefix: "/erp/api/work-centers" });
|
|
108
|
+
// Public endpoint to expose client configuration
|
|
109
|
+
fastify.get("/erp/api/client-config", { schema: { hide: true } }, () => ({
|
|
110
|
+
publicRead: process.env.PUBLIC_READ === "true",
|
|
111
|
+
supervisorAuth: isSupervisorAuth(),
|
|
112
|
+
}));
|
|
113
|
+
return Promise.resolve();
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=erpRoutes.js.map
|
package/dist/erpServer.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
2
|
import "./schema-registry.js";
|
|
3
|
-
import { expandNaisysFolder } from "@naisys/common-node";
|
|
3
|
+
import { cwdWithTilde, ensureDotEnv, expandNaisysFolder, promptSuperAdminPassword, runSetupWizard, } from "@naisys/common-node";
|
|
4
4
|
expandNaisysFolder();
|
|
5
5
|
// Important to load dotenv before any other imports, to ensure environment variables are available
|
|
6
6
|
import cookie from "@fastify/cookie";
|
|
@@ -9,59 +9,31 @@ import multipart from "@fastify/multipart";
|
|
|
9
9
|
import { fastifyRateLimit as rateLimit } from "@fastify/rate-limit";
|
|
10
10
|
import staticFiles from "@fastify/static";
|
|
11
11
|
import swagger from "@fastify/swagger";
|
|
12
|
-
import { commonErrorHandler, registerLenientJsonParser, registerSecurityHeaders, } from "@naisys/common";
|
|
12
|
+
import { commonErrorHandler, registerLenientJsonParser, registerSecurityHeaders, SUPER_ADMIN_USERNAME, } from "@naisys/common";
|
|
13
|
+
import { createFileLogger } from "@naisys/common-node";
|
|
13
14
|
import { createHubDatabaseClient, deployPrismaMigrations, } from "@naisys/hub-database";
|
|
14
|
-
import { createSupervisorDatabaseClient
|
|
15
|
+
import { createSupervisorDatabaseClient } from "@naisys/supervisor-database";
|
|
15
16
|
import Fastify from "fastify";
|
|
16
17
|
import { jsonSchemaTransform, jsonSchemaTransformObject, serializerCompiler, validatorCompiler, } from "fastify-type-provider-zod";
|
|
17
18
|
import path from "path";
|
|
18
|
-
import pino from "pino";
|
|
19
19
|
import { fileURLToPath } from "url";
|
|
20
|
+
import { takeCoverage } from "v8";
|
|
20
21
|
import { registerApiReference } from "./api-reference.js";
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
|
|
29
|
-
import itemFieldRoutes from "./routes/item-fields.js";
|
|
30
|
-
import itemInstanceRoutes from "./routes/item-instances.js";
|
|
31
|
-
import itemRoutes from "./routes/items.js";
|
|
32
|
-
import laborTicketRoutes from "./routes/labor-tickets.js";
|
|
33
|
-
import operationDependencyRoutes from "./routes/operation-dependencies.js";
|
|
34
|
-
import operationFieldRefRoutes from "./routes/operation-field-refs.js";
|
|
35
|
-
import operationRunCommentRoutes from "./routes/operation-run-comments.js";
|
|
36
|
-
import operationRunTransitionRoutes from "./routes/operation-run-transitions.js";
|
|
37
|
-
import operationRunRoutes from "./routes/operation-runs.js";
|
|
38
|
-
import operationRoutes from "./routes/operations.js";
|
|
39
|
-
import orderRevisionTransitionRoutes from "./routes/order-revision-transitions.js";
|
|
40
|
-
import orderRevisionRoutes from "./routes/order-revisions.js";
|
|
41
|
-
import orderRunTransitionRoutes from "./routes/order-run-transitions.js";
|
|
42
|
-
import orderRunRoutes from "./routes/order-runs.js";
|
|
43
|
-
import orderRoutes from "./routes/orders.js";
|
|
44
|
-
import rootRoute from "./routes/root.js";
|
|
45
|
-
import schemaRoutes from "./routes/schemas.js";
|
|
46
|
-
import stepFieldAttachmentRoutes from "./routes/step-field-attachments.js";
|
|
47
|
-
import stepFieldRoutes from "./routes/step-fields.js";
|
|
48
|
-
import stepRunFieldRoutes from "./routes/step-run-fields.js";
|
|
49
|
-
import stepRunTransitionRoutes from "./routes/step-run-transitions.js";
|
|
50
|
-
import stepRunRoutes from "./routes/step-runs.js";
|
|
51
|
-
import stepRoutes from "./routes/steps.js";
|
|
52
|
-
import userPermissionRoutes from "./routes/user-permissions.js";
|
|
53
|
-
import userRoutes from "./routes/users.js";
|
|
54
|
-
import workCenterRoutes from "./routes/work-centers.js";
|
|
55
|
-
import { isSupervisorAuth } from "./supervisorAuth.js";
|
|
56
|
-
import { ensureLocalSuperAdmin, ensureSupervisorSuperAdmin, resetLocalPassword, } from "./userService.js";
|
|
57
|
-
export { enableSupervisorAuth } from "./supervisorAuth.js";
|
|
22
|
+
import { ERP_DB_VERSION, erpDbPath } from "./database/dbConfig.js";
|
|
23
|
+
import { initErpDb } from "./database/erpDb.js";
|
|
24
|
+
import { erpRoutes } from "./erpRoutes.js";
|
|
25
|
+
import { registerAuthMiddleware } from "./middleware/auth-middleware.js";
|
|
26
|
+
import { isSupervisorAuth } from "./middleware/supervisorAuth.js";
|
|
27
|
+
import { backfillOpRunTokens } from "./services/production/labor-ticket-backfill.js";
|
|
28
|
+
import { ensureLocalSuperAdmin, ensureSupervisorSuperAdmin, } from "./services/user-service.js";
|
|
29
|
+
export { enableSupervisorAuth } from "./middleware/supervisorAuth.js";
|
|
58
30
|
const __filename = fileURLToPath(import.meta.url);
|
|
59
31
|
const __dirname = path.dirname(__filename);
|
|
60
32
|
/**
|
|
61
33
|
* Fastify plugin that registers ERP routes and static files.
|
|
62
34
|
* Can be used standalone or registered inside another Fastify app (e.g. supervisor).
|
|
63
35
|
*/
|
|
64
|
-
export const erpPlugin = async (fastify) => {
|
|
36
|
+
export const erpPlugin = async (fastify, opts) => {
|
|
65
37
|
const isProd = process.env.NODE_ENV === "production";
|
|
66
38
|
// Cookie plugin (guard for supervisor embedding)
|
|
67
39
|
if (!fastify.hasDecorator("parseCookie")) {
|
|
@@ -73,7 +45,7 @@ export const erpPlugin = async (fastify) => {
|
|
|
73
45
|
}
|
|
74
46
|
// Rate limiting — moderate global default, strict overrides on sensitive routes
|
|
75
47
|
await fastify.register(rateLimit, {
|
|
76
|
-
max: 500,
|
|
48
|
+
max: Number(process.env.ERP_API_RATE_LIMIT) || 500,
|
|
77
49
|
timeWindow: "1 minute",
|
|
78
50
|
allowList: (request) => !request.url.match(/^\/(supervisor|erp)\/api\//),
|
|
79
51
|
});
|
|
@@ -94,17 +66,17 @@ export const erpPlugin = async (fastify) => {
|
|
|
94
66
|
throw new Error("[ERP] Supervisor database not available. Required for supervisor auth.");
|
|
95
67
|
}
|
|
96
68
|
await ensureSupervisorSuperAdmin();
|
|
69
|
+
await backfillOpRunTokens();
|
|
97
70
|
}
|
|
98
71
|
else {
|
|
99
|
-
await ensureLocalSuperAdmin();
|
|
72
|
+
await ensureLocalSuperAdmin(opts.superAdminPassword);
|
|
100
73
|
}
|
|
101
74
|
fastify.setErrorHandler(commonErrorHandler);
|
|
102
75
|
registerAuthMiddleware(fastify);
|
|
103
76
|
// ERP-specific file logger (works in both standalone and hosted mode)
|
|
104
77
|
const naisysFolder = process.env.NAISYS_FOLDER;
|
|
105
78
|
if (naisysFolder) {
|
|
106
|
-
const
|
|
107
|
-
const erpFileLogger = pino({ level: "info" }, pino.destination({ dest: erpLogDest, mkdir: true }));
|
|
79
|
+
const erpFileLogger = createFileLogger("erp.log");
|
|
108
80
|
erpFileLogger.info("ERP plugin initialized");
|
|
109
81
|
fastify.addHook("onResponse", async (request, reply) => {
|
|
110
82
|
if (!request.url.startsWith("/erp/api"))
|
|
@@ -123,86 +95,8 @@ export const erpPlugin = async (fastify) => {
|
|
|
123
95
|
}, `${request.method} ${request.url} error`);
|
|
124
96
|
});
|
|
125
97
|
}
|
|
126
|
-
// API routes
|
|
127
|
-
fastify.register(
|
|
128
|
-
fastify.register(auditRoutes, { prefix: "/erp/api/audit" });
|
|
129
|
-
fastify.register(authRoutes, { prefix: "/erp/api/auth" });
|
|
130
|
-
fastify.register(dispatchRoutes, { prefix: "/erp/api/dispatch" });
|
|
131
|
-
fastify.register(inventoryRoutes, { prefix: "/erp/api/inventory" });
|
|
132
|
-
fastify.register(rootRoute, { prefix: "/erp/api" });
|
|
133
|
-
fastify.register(itemRoutes, { prefix: "/erp/api/items" });
|
|
134
|
-
fastify.register(itemFieldRoutes, {
|
|
135
|
-
prefix: "/erp/api/items/:key/fields",
|
|
136
|
-
});
|
|
137
|
-
fastify.register(itemInstanceRoutes, {
|
|
138
|
-
prefix: "/erp/api/items/:key/instances",
|
|
139
|
-
});
|
|
140
|
-
fastify.register(orderRoutes, {
|
|
141
|
-
prefix: "/erp/api/orders",
|
|
142
|
-
});
|
|
143
|
-
fastify.register(orderRevisionRoutes, {
|
|
144
|
-
prefix: "/erp/api/orders/:orderKey/revs",
|
|
145
|
-
});
|
|
146
|
-
fastify.register(orderRevisionTransitionRoutes, {
|
|
147
|
-
prefix: "/erp/api/orders/:orderKey/revs",
|
|
148
|
-
});
|
|
149
|
-
fastify.register(orderRunRoutes, {
|
|
150
|
-
prefix: "/erp/api/orders/:orderKey/runs",
|
|
151
|
-
});
|
|
152
|
-
fastify.register(orderRunTransitionRoutes, {
|
|
153
|
-
prefix: "/erp/api/orders/:orderKey/runs",
|
|
154
|
-
});
|
|
155
|
-
fastify.register(operationRoutes, {
|
|
156
|
-
prefix: "/erp/api/orders/:orderKey/revs/:revNo/ops",
|
|
157
|
-
});
|
|
158
|
-
fastify.register(operationDependencyRoutes, {
|
|
159
|
-
prefix: "/erp/api/orders/:orderKey/revs/:revNo/ops/:seqNo/deps",
|
|
160
|
-
});
|
|
161
|
-
fastify.register(operationFieldRefRoutes, {
|
|
162
|
-
prefix: "/erp/api/orders/:orderKey/revs/:revNo/ops/:seqNo/field-refs",
|
|
163
|
-
});
|
|
164
|
-
fastify.register(operationRunRoutes, {
|
|
165
|
-
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops",
|
|
166
|
-
});
|
|
167
|
-
fastify.register(operationRunTransitionRoutes, {
|
|
168
|
-
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops",
|
|
169
|
-
});
|
|
170
|
-
fastify.register(laborTicketRoutes, {
|
|
171
|
-
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/labor",
|
|
172
|
-
});
|
|
173
|
-
fastify.register(operationRunCommentRoutes, {
|
|
174
|
-
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/comments",
|
|
175
|
-
});
|
|
176
|
-
fastify.register(stepRunRoutes, {
|
|
177
|
-
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/steps",
|
|
178
|
-
});
|
|
179
|
-
fastify.register(stepRunTransitionRoutes, {
|
|
180
|
-
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/steps",
|
|
181
|
-
});
|
|
182
|
-
fastify.register(stepRunFieldRoutes, {
|
|
183
|
-
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/steps",
|
|
184
|
-
});
|
|
185
|
-
fastify.register(stepFieldAttachmentRoutes, {
|
|
186
|
-
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/steps/:stepSeqNo/fields/:fieldSeqNo/attachments",
|
|
187
|
-
});
|
|
188
|
-
fastify.register(stepFieldAttachmentRoutes, {
|
|
189
|
-
prefix: "/erp/api/orders/:orderKey/runs/:runNo/ops/:seqNo/steps/:stepSeqNo/sets/:setIndex/fields/:fieldSeqNo/attachments",
|
|
190
|
-
});
|
|
191
|
-
fastify.register(stepRoutes, {
|
|
192
|
-
prefix: "/erp/api/orders/:orderKey/revs/:revNo/ops/:seqNo/steps",
|
|
193
|
-
});
|
|
194
|
-
fastify.register(stepFieldRoutes, {
|
|
195
|
-
prefix: "/erp/api/orders/:orderKey/revs/:revNo/ops/:seqNo/steps/:stepSeqNo/fields",
|
|
196
|
-
});
|
|
197
|
-
fastify.register(schemaRoutes, { prefix: "/erp/api/schemas" });
|
|
198
|
-
fastify.register(userRoutes, { prefix: "/erp/api/users" });
|
|
199
|
-
fastify.register(userPermissionRoutes, { prefix: "/erp/api/users" });
|
|
200
|
-
fastify.register(workCenterRoutes, { prefix: "/erp/api/work-centers" });
|
|
201
|
-
// Public endpoint to expose client configuration (publicRead, etc.)
|
|
202
|
-
fastify.get("/erp/api/client-config", { schema: { hide: true } }, () => ({
|
|
203
|
-
publicRead: process.env.PUBLIC_READ === "true",
|
|
204
|
-
supervisorAuth: isSupervisorAuth(),
|
|
205
|
-
}));
|
|
98
|
+
// API routes
|
|
99
|
+
await fastify.register(erpRoutes);
|
|
206
100
|
registerApiReference(fastify);
|
|
207
101
|
// In production, serve the client build
|
|
208
102
|
if (isProd) {
|
|
@@ -234,10 +128,13 @@ export const erpPlugin = async (fastify) => {
|
|
|
234
128
|
});
|
|
235
129
|
}
|
|
236
130
|
};
|
|
237
|
-
async function startServer() {
|
|
131
|
+
async function startServer(wizardRan) {
|
|
238
132
|
const isProd = process.env.NODE_ENV === "production";
|
|
239
133
|
const fastify = Fastify({
|
|
240
134
|
pluginTimeout: 60_000,
|
|
135
|
+
// trustProxy: TLS terminates at the reverse proxy, so honor X-Forwarded-*
|
|
136
|
+
// headers — otherwise request.protocol reads the internal http hop.
|
|
137
|
+
trustProxy: true,
|
|
241
138
|
logger: {
|
|
242
139
|
transport: {
|
|
243
140
|
target: "pino-pretty",
|
|
@@ -249,7 +146,7 @@ async function startServer() {
|
|
|
249
146
|
fastify.setSerializerCompiler(serializerCompiler);
|
|
250
147
|
registerLenientJsonParser(fastify);
|
|
251
148
|
await fastify.register(cors, {
|
|
252
|
-
origin: isProd ? false : ["http://localhost:
|
|
149
|
+
origin: isProd ? false : ["http://localhost:2202"],
|
|
253
150
|
credentials: true,
|
|
254
151
|
});
|
|
255
152
|
registerSecurityHeaders(fastify, { enforceHsts: isProd });
|
|
@@ -268,54 +165,87 @@ async function startServer() {
|
|
|
268
165
|
fastify.get("/", { schema: { hide: true } }, async (_request, reply) => {
|
|
269
166
|
return reply.redirect("/erp/");
|
|
270
167
|
});
|
|
271
|
-
|
|
272
|
-
|
|
168
|
+
if (process.env.NODE_V8_COVERAGE) {
|
|
169
|
+
fastify.post("/erp/api/__coverage/flush", { schema: { hide: true } }, () => {
|
|
170
|
+
takeCoverage();
|
|
171
|
+
return { ok: true };
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
const superAdminPassword = wizardRan && !isSupervisorAuth()
|
|
175
|
+
? await promptSuperAdminPassword("ERP Setup")
|
|
176
|
+
: undefined;
|
|
177
|
+
await fastify.register(erpPlugin, { superAdminPassword });
|
|
178
|
+
const port = Number(process.env.SERVER_PORT) || 3302;
|
|
273
179
|
const host = isProd ? "0.0.0.0" : "localhost";
|
|
274
180
|
try {
|
|
275
181
|
await fastify.listen({ port, host });
|
|
276
182
|
console.log(`[ERP] Running on http://${host}:${port}/erp`);
|
|
277
183
|
console.log(`[ERP] API Reference: http://${host}:${port}/erp/api-reference`);
|
|
278
184
|
console.log(`[ERP] Auth mode: ${isSupervisorAuth() ? "supervisor" : "standalone"}`);
|
|
185
|
+
if (!isSupervisorAuth()) {
|
|
186
|
+
console.log(`[ERP] Sign in as '${SUPER_ADMIN_USERNAME}' with the password set during setup. Use --setup to change it.`);
|
|
187
|
+
}
|
|
279
188
|
}
|
|
280
189
|
catch (err) {
|
|
281
190
|
console.error("[ERP] Failed to start:", err);
|
|
282
|
-
|
|
191
|
+
try {
|
|
192
|
+
await fastify.close();
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// Startup already failed; preserve the original error as the cause.
|
|
196
|
+
}
|
|
197
|
+
throw err;
|
|
283
198
|
}
|
|
199
|
+
return fastify;
|
|
284
200
|
}
|
|
285
201
|
// Start server if this file is run directly
|
|
286
202
|
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
password,
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
void resetLocalPassword();
|
|
315
|
-
}
|
|
203
|
+
const erpWizardConfig = {
|
|
204
|
+
title: "NAISYS ERP Setup",
|
|
205
|
+
sections: [
|
|
206
|
+
{
|
|
207
|
+
type: "fields",
|
|
208
|
+
comment: "ERP configuration",
|
|
209
|
+
fields: [
|
|
210
|
+
{
|
|
211
|
+
key: "NAISYS_FOLDER",
|
|
212
|
+
label: "NAISYS Data Folder",
|
|
213
|
+
defaultValue: cwdWithTilde(),
|
|
214
|
+
},
|
|
215
|
+
{ key: "SERVER_PORT", label: "Server Port" },
|
|
216
|
+
{ key: "SUPERVISOR_AUTH", label: "Use Supervisor for Auth" },
|
|
217
|
+
],
|
|
218
|
+
},
|
|
219
|
+
],
|
|
220
|
+
};
|
|
221
|
+
const erpExampleUrl = new URL("../.env.example", import.meta.url);
|
|
222
|
+
let wizardRan = false;
|
|
223
|
+
if (process.argv.includes("--setup")) {
|
|
224
|
+
wizardRan = await runSetupWizard(path.resolve(".env"), erpExampleUrl, erpWizardConfig);
|
|
225
|
+
expandNaisysFolder();
|
|
316
226
|
}
|
|
317
|
-
|
|
318
|
-
|
|
227
|
+
if (process.env.NAISYS_SKIP_DOTENV_CHECK !== "1") {
|
|
228
|
+
wizardRan =
|
|
229
|
+
(await ensureDotEnv(erpExampleUrl, erpWizardConfig)) || wizardRan;
|
|
319
230
|
}
|
|
231
|
+
const fastify = await startServer(wizardRan);
|
|
232
|
+
let shuttingDown = false;
|
|
233
|
+
const handleShutdown = async (signal) => {
|
|
234
|
+
if (shuttingDown) {
|
|
235
|
+
console.log("[ERP] Force exit");
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
shuttingDown = true;
|
|
239
|
+
console.log(`[ERP] Shutting down (${signal})...`);
|
|
240
|
+
try {
|
|
241
|
+
await fastify.close();
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
console.error("[ERP] Error during fastify.close():", err);
|
|
245
|
+
}
|
|
246
|
+
process.exit(0);
|
|
247
|
+
};
|
|
248
|
+
process.on("SIGTERM", () => void handleShutdown("SIGTERM"));
|
|
249
|
+
process.on("SIGINT", () => void handleShutdown("SIGINT"));
|
|
320
250
|
}
|
|
321
251
|
//# sourceMappingURL=erpServer.js.map
|
package/dist/error-handler.js
CHANGED
|
@@ -2,6 +2,9 @@ function send(reply, statusCode, error, message) {
|
|
|
2
2
|
reply.status(statusCode);
|
|
3
3
|
return { statusCode, error, message };
|
|
4
4
|
}
|
|
5
|
+
export function badRequest(reply, message) {
|
|
6
|
+
return send(reply, 400, "Bad Request", message);
|
|
7
|
+
}
|
|
5
8
|
export function notFound(reply, message) {
|
|
6
9
|
return send(reply, 404, "Not Found", message);
|
|
7
10
|
}
|