create-prisma-php-app 4.2.2-beta → 4.2.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/bootstrap.php +406 -251
- package/dist/index.js +1 -1
- package/dist/prisma-php.js +1 -1
- package/dist/public/js/pp-reactive-v1.js +1 -1
- package/dist/settings/bs-config.ts +16 -3
- package/dist/settings/vite-plugins/generate-global-types.ts +246 -0
- package/dist/src/Lib/Auth/Auth.php +53 -50
- package/dist/src/app/index.php +2 -2
- package/dist/src/app/layout.php +1 -2
- package/dist/src/app/not-found.php +2 -2
- package/dist/tsconfig.json +1 -1
- package/dist/vite.config.ts +20 -6
- package/package.json +4 -4
|
@@ -3,7 +3,7 @@ import { writeFileSync, existsSync, mkdirSync } from "fs";
|
|
|
3
3
|
import browserSync, { BrowserSyncInstance } from "browser-sync";
|
|
4
4
|
import prismaPhpConfigJson from "../prisma-php.json";
|
|
5
5
|
import { generateFileListJson } from "./files-list.js";
|
|
6
|
-
import { join, dirname } from "path";
|
|
6
|
+
import { join, dirname, relative } from "path";
|
|
7
7
|
import { getFileMeta, PUBLIC_DIR, SRC_DIR } from "./utils.js";
|
|
8
8
|
import { updateAllClassLogs } from "./class-log.js";
|
|
9
9
|
import {
|
|
@@ -15,9 +15,10 @@ import { checkComponentImports } from "./component-import-checker";
|
|
|
15
15
|
import { DebouncedWorker, createSrcWatcher, DEFAULT_AWF } from "./utils.js";
|
|
16
16
|
|
|
17
17
|
const { __dirname } = getFileMeta();
|
|
18
|
-
|
|
19
18
|
const bs: BrowserSyncInstance = browserSync.create();
|
|
20
19
|
|
|
20
|
+
const PUBLIC_IGNORE_DIRS = [''];
|
|
21
|
+
|
|
21
22
|
const pipeline = new DebouncedWorker(
|
|
22
23
|
async () => {
|
|
23
24
|
await generateFileListJson();
|
|
@@ -68,7 +69,19 @@ createSrcWatcher(join(SRC_DIR, "**", "*"), {
|
|
|
68
69
|
});
|
|
69
70
|
|
|
70
71
|
createSrcWatcher(join(PUBLIC_DIR, "**", "*"), {
|
|
71
|
-
onEvent: (_ev,
|
|
72
|
+
onEvent: (_ev, abs, _) => {
|
|
73
|
+
const relFromPublic = relative(PUBLIC_DIR, abs);
|
|
74
|
+
const normalized = relFromPublic.replace(/\\/g, "/");
|
|
75
|
+
|
|
76
|
+
const segments = normalized.split("/").filter(Boolean);
|
|
77
|
+
const firstSegment = segments[0] || "";
|
|
78
|
+
|
|
79
|
+
if (PUBLIC_IGNORE_DIRS.includes(firstSegment)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
publicPipeline.schedule(relFromPublic);
|
|
84
|
+
},
|
|
72
85
|
awaitWriteFinish: DEFAULT_AWF,
|
|
73
86
|
logPrefix: "watch-public",
|
|
74
87
|
usePolling: true,
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { writeFileSync, mkdirSync, existsSync, readFileSync } from "fs";
|
|
4
|
+
import ts from "typescript";
|
|
5
|
+
|
|
6
|
+
export function generateGlobalTypes(): Plugin {
|
|
7
|
+
const dtsPath = path.resolve(process.cwd(), ".pp", "global-functions.d.ts");
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
name: "generate-global-types",
|
|
11
|
+
|
|
12
|
+
buildStart() {
|
|
13
|
+
const mainPath = path.resolve(process.cwd(), "ts", "main.ts");
|
|
14
|
+
|
|
15
|
+
if (!existsSync(mainPath)) {
|
|
16
|
+
console.warn("⚠️ ts/main.ts not found, skipping type generation");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const content = readFileSync(mainPath, "utf-8");
|
|
21
|
+
const globals = parseGlobalSingletons(content, mainPath);
|
|
22
|
+
|
|
23
|
+
if (globals.length === 0) {
|
|
24
|
+
console.warn("⚠️ No createGlobalSingleton calls found");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
generateDtsWithTypeChecker(globals, dtsPath, mainPath);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
interface GlobalDeclaration {
|
|
33
|
+
name: string;
|
|
34
|
+
importPath: string;
|
|
35
|
+
exportName: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function parseGlobalSingletons(
|
|
39
|
+
content: string,
|
|
40
|
+
filePath: string
|
|
41
|
+
): GlobalDeclaration[] {
|
|
42
|
+
const sf = ts.createSourceFile(
|
|
43
|
+
filePath,
|
|
44
|
+
content,
|
|
45
|
+
ts.ScriptTarget.Latest,
|
|
46
|
+
true
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const globals: GlobalDeclaration[] = [];
|
|
50
|
+
const importMap = new Map<string, { path: string; originalName: string }>();
|
|
51
|
+
|
|
52
|
+
sf.statements.forEach((stmt) => {
|
|
53
|
+
if (ts.isImportDeclaration(stmt) && stmt.importClause) {
|
|
54
|
+
const moduleSpecifier = (stmt.moduleSpecifier as ts.StringLiteral).text;
|
|
55
|
+
|
|
56
|
+
if (stmt.importClause.namedBindings) {
|
|
57
|
+
if (ts.isNamedImports(stmt.importClause.namedBindings)) {
|
|
58
|
+
stmt.importClause.namedBindings.elements.forEach((element) => {
|
|
59
|
+
const localName = element.name.text;
|
|
60
|
+
const importedName = element.propertyName
|
|
61
|
+
? element.propertyName.text
|
|
62
|
+
: localName;
|
|
63
|
+
|
|
64
|
+
importMap.set(localName, {
|
|
65
|
+
path: moduleSpecifier,
|
|
66
|
+
originalName: importedName,
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
function visit(node: ts.Node) {
|
|
75
|
+
if (
|
|
76
|
+
ts.isCallExpression(node) &&
|
|
77
|
+
ts.isIdentifier(node.expression) &&
|
|
78
|
+
node.expression.text === "createGlobalSingleton"
|
|
79
|
+
) {
|
|
80
|
+
if (node.arguments.length >= 2) {
|
|
81
|
+
const nameArg = node.arguments[0];
|
|
82
|
+
const valueArg = node.arguments[1];
|
|
83
|
+
|
|
84
|
+
if (ts.isStringLiteral(nameArg) && ts.isIdentifier(valueArg)) {
|
|
85
|
+
const name = nameArg.text;
|
|
86
|
+
const variable = valueArg.text;
|
|
87
|
+
const importInfo = importMap.get(variable);
|
|
88
|
+
|
|
89
|
+
if (importInfo) {
|
|
90
|
+
globals.push({
|
|
91
|
+
name,
|
|
92
|
+
importPath: importInfo.path,
|
|
93
|
+
exportName: importInfo.originalName,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
ts.forEachChild(node, visit);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
visit(sf);
|
|
104
|
+
return globals;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function generateDtsWithTypeChecker(
|
|
108
|
+
globals: GlobalDeclaration[],
|
|
109
|
+
dtsPath: string,
|
|
110
|
+
mainPath: string
|
|
111
|
+
) {
|
|
112
|
+
const configPath = ts.findConfigFile(
|
|
113
|
+
process.cwd(),
|
|
114
|
+
ts.sys.fileExists,
|
|
115
|
+
"tsconfig.json"
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const { config } = configPath
|
|
119
|
+
? ts.readConfigFile(configPath, ts.sys.readFile)
|
|
120
|
+
: { config: {} };
|
|
121
|
+
|
|
122
|
+
const { options } = ts.parseJsonConfigFileContent(
|
|
123
|
+
config,
|
|
124
|
+
ts.sys,
|
|
125
|
+
process.cwd()
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const program = ts.createProgram([mainPath], options);
|
|
129
|
+
const checker = program.getTypeChecker();
|
|
130
|
+
const sourceFile = program.getSourceFile(mainPath);
|
|
131
|
+
|
|
132
|
+
if (!sourceFile) {
|
|
133
|
+
console.warn("⚠️ Could not load main.ts for type checking");
|
|
134
|
+
generateFallbackDts(globals, dtsPath);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const signatures = new Map<string, string>();
|
|
139
|
+
|
|
140
|
+
const importMap = new Map<string, ts.ImportDeclaration>();
|
|
141
|
+
sourceFile.statements.forEach((stmt) => {
|
|
142
|
+
if (ts.isImportDeclaration(stmt) && stmt.importClause?.namedBindings) {
|
|
143
|
+
if (ts.isNamedImports(stmt.importClause.namedBindings)) {
|
|
144
|
+
stmt.importClause.namedBindings.elements.forEach((element) => {
|
|
145
|
+
importMap.set(element.name.text, stmt);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
globals.forEach(({ name, exportName }) => {
|
|
152
|
+
try {
|
|
153
|
+
const importDecl = importMap.get(exportName);
|
|
154
|
+
if (!importDecl || !importDecl.importClause?.namedBindings) {
|
|
155
|
+
signatures.set(name, "(...args: any[]) => any");
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (ts.isNamedImports(importDecl.importClause.namedBindings)) {
|
|
160
|
+
const importSpec = importDecl.importClause.namedBindings.elements.find(
|
|
161
|
+
(el) => el.name.text === exportName
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
if (importSpec) {
|
|
165
|
+
const symbol = checker.getSymbolAtLocation(importSpec.name);
|
|
166
|
+
if (symbol) {
|
|
167
|
+
const type = checker.getTypeOfSymbolAtLocation(
|
|
168
|
+
symbol,
|
|
169
|
+
importSpec.name
|
|
170
|
+
);
|
|
171
|
+
const signature = checker.typeToString(
|
|
172
|
+
type,
|
|
173
|
+
undefined,
|
|
174
|
+
ts.TypeFormatFlags.NoTruncation
|
|
175
|
+
);
|
|
176
|
+
signatures.set(name, signature);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
signatures.set(name, "(...args: any[]) => any");
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.warn(`⚠️ Failed to extract type for ${name}:`, error);
|
|
185
|
+
signatures.set(name, "(...args: any[]) => any");
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const declarations = globals
|
|
190
|
+
.map(({ name }) => {
|
|
191
|
+
const sig = signatures.get(name) || "(...args: any[]) => any";
|
|
192
|
+
return ` const ${name}: ${sig};`;
|
|
193
|
+
})
|
|
194
|
+
.join("\n");
|
|
195
|
+
|
|
196
|
+
const windowDeclarations = globals
|
|
197
|
+
.map(({ name }) => ` ${name}: typeof globalThis.${name};`)
|
|
198
|
+
.join("\n");
|
|
199
|
+
|
|
200
|
+
const content = `// Auto-generated by Vite plugin
|
|
201
|
+
// Do not edit manually - regenerate with: npm run dev or npm run build
|
|
202
|
+
// Source: ts/main.ts
|
|
203
|
+
|
|
204
|
+
declare global {
|
|
205
|
+
${declarations}
|
|
206
|
+
|
|
207
|
+
interface Window {
|
|
208
|
+
${windowDeclarations}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export {};
|
|
213
|
+
`;
|
|
214
|
+
|
|
215
|
+
const dir = path.dirname(dtsPath);
|
|
216
|
+
if (!existsSync(dir)) {
|
|
217
|
+
mkdirSync(dir, { recursive: true });
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
writeFileSync(dtsPath, content, "utf-8");
|
|
221
|
+
console.log(`✅ Generated ${path.relative(process.cwd(), dtsPath)}`);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function generateFallbackDts(globals: GlobalDeclaration[], dtsPath: string) {
|
|
225
|
+
const declarations = globals
|
|
226
|
+
.map(({ name }) => ` const ${name}: (...args: any[]) => any;`)
|
|
227
|
+
.join("\n");
|
|
228
|
+
|
|
229
|
+
const windowDeclarations = globals
|
|
230
|
+
.map(({ name }) => ` ${name}: typeof globalThis.${name};`)
|
|
231
|
+
.join("\n");
|
|
232
|
+
|
|
233
|
+
const content = `// Auto-generated by Vite plugin
|
|
234
|
+
declare global {
|
|
235
|
+
${declarations}
|
|
236
|
+
|
|
237
|
+
interface Window {
|
|
238
|
+
${windowDeclarations}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export {};
|
|
243
|
+
`;
|
|
244
|
+
|
|
245
|
+
writeFileSync(dtsPath, content, "utf-8");
|
|
246
|
+
}
|
|
@@ -29,21 +29,12 @@ class Auth
|
|
|
29
29
|
private string $secretKey;
|
|
30
30
|
private string $defaultTokenValidity = '1h'; // Default to 1 hour
|
|
31
31
|
|
|
32
|
-
/**
|
|
33
|
-
* Private constructor to prevent direct instantiation.
|
|
34
|
-
* Use Auth::getInstance() to get the singleton instance.
|
|
35
|
-
*/
|
|
36
32
|
private function __construct()
|
|
37
33
|
{
|
|
38
34
|
$this->secretKey = $_ENV['AUTH_SECRET'] ?? 'CD24eEv4qbsC5LOzqeaWbcr58mBMSvA4Mkii8GjRiHkt';
|
|
39
35
|
self::$cookieName = self::getCookieName();
|
|
40
36
|
}
|
|
41
37
|
|
|
42
|
-
/**
|
|
43
|
-
* Returns the singleton instance of the Auth class.
|
|
44
|
-
*
|
|
45
|
-
* @return Auth The singleton instance.
|
|
46
|
-
*/
|
|
47
38
|
public static function getInstance(): Auth
|
|
48
39
|
{
|
|
49
40
|
if (self::$instance === null) {
|
|
@@ -53,33 +44,20 @@ class Auth
|
|
|
53
44
|
}
|
|
54
45
|
|
|
55
46
|
/**
|
|
56
|
-
* Authenticates a user and generates a JWT
|
|
57
|
-
*
|
|
58
|
-
* the token's expiration time, sets the necessary payload, and encodes it into a JWT.
|
|
59
|
-
* If possible (HTTP headers not yet sent), it also sets cookies with the JWT for client-side storage.
|
|
47
|
+
* Authenticates a user and generates a JWT.
|
|
48
|
+
* Optionally redirects the user to a default or custom URL.
|
|
60
49
|
*
|
|
61
|
-
* @param mixed $data User data
|
|
62
|
-
*
|
|
63
|
-
* @param string
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
50
|
+
* @param mixed $data User data (string or AuthRole).
|
|
51
|
+
* @param string|null $tokenValidity Duration token is valid for (e.g., '1h'). Default is '1h'.
|
|
52
|
+
* @param bool|string $redirect
|
|
53
|
+
* - If `false` (default): No redirect occurs; returns the JWT.
|
|
54
|
+
* - If `true`: Redirects to `AuthConfig::DEFAULT_SIGNIN_REDIRECT`.
|
|
55
|
+
* - If `string`: Redirects to the specified URL (e.g., '/dashboard').
|
|
67
56
|
*
|
|
68
57
|
* @return string Returns the encoded JWT as a string.
|
|
69
|
-
*
|
|
70
|
-
* @throws InvalidArgumentException Thrown if the secret key is not set or if the duration format is invalid.
|
|
71
|
-
*
|
|
72
|
-
* Example:
|
|
73
|
-
* $auth = Auth::getInstance();
|
|
74
|
-
* $auth->setSecretKey('your_secret_key');
|
|
75
|
-
* try {
|
|
76
|
-
* $jwt = $auth->signIn('Admin', '1h');
|
|
77
|
-
* echo "JWT: " . $jwt;
|
|
78
|
-
* } catch (InvalidArgumentException $e) {
|
|
79
|
-
* echo "Error: " . $e->getMessage();
|
|
80
|
-
* }
|
|
58
|
+
* @throws InvalidArgumentException
|
|
81
59
|
*/
|
|
82
|
-
public function signIn($data, ?string $tokenValidity = null): string
|
|
60
|
+
public function signIn($data, ?string $tokenValidity = null, bool|string $redirect = false): string
|
|
83
61
|
{
|
|
84
62
|
if (!$this->secretKey) {
|
|
85
63
|
throw new InvalidArgumentException("Secret key is required for authentication.");
|
|
@@ -96,14 +74,20 @@ class Auth
|
|
|
96
74
|
'exp' => $expirationTime,
|
|
97
75
|
];
|
|
98
76
|
|
|
99
|
-
// Set the payload in the session
|
|
100
77
|
$_SESSION[self::PAYLOAD_SESSION_KEY] = $payload;
|
|
101
78
|
|
|
102
|
-
// Encode the JWT
|
|
103
79
|
$jwt = JWT::encode($payload, $this->secretKey, 'HS256');
|
|
104
80
|
|
|
105
81
|
if (!headers_sent()) {
|
|
106
82
|
$this->setCookies($jwt, $expirationTime);
|
|
83
|
+
|
|
84
|
+
$this->rotateCsrfToken();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if ($redirect === true) {
|
|
88
|
+
Request::redirect(AuthConfig::DEFAULT_SIGNIN_REDIRECT);
|
|
89
|
+
} elseif (is_string($redirect) && !empty($redirect)) {
|
|
90
|
+
Request::redirect($redirect);
|
|
107
91
|
}
|
|
108
92
|
|
|
109
93
|
return $jwt;
|
|
@@ -184,19 +168,12 @@ class Auth
|
|
|
184
168
|
public function verifyToken(?string $jwt): ?object
|
|
185
169
|
{
|
|
186
170
|
try {
|
|
187
|
-
if (!$jwt)
|
|
188
|
-
return null;
|
|
189
|
-
}
|
|
171
|
+
if (!$jwt) return null;
|
|
190
172
|
|
|
191
173
|
$token = JWT::decode($jwt, new Key($this->secretKey, 'HS256'));
|
|
192
174
|
|
|
193
|
-
if (empty($token->{Auth::PAYLOAD_NAME}))
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (isset($token->exp) && time() >= $token->exp) {
|
|
198
|
-
return null;
|
|
199
|
-
}
|
|
175
|
+
if (empty($token->{Auth::PAYLOAD_NAME})) return null;
|
|
176
|
+
if (isset($token->exp) && time() >= $token->exp) return null;
|
|
200
177
|
|
|
201
178
|
return $token;
|
|
202
179
|
} catch (Exception) {
|
|
@@ -228,7 +205,6 @@ class Auth
|
|
|
228
205
|
}
|
|
229
206
|
|
|
230
207
|
$expirationTime = $this->calculateExpirationTime($tokenValidity ?? $this->defaultTokenValidity);
|
|
231
|
-
|
|
232
208
|
$decodedToken->exp = $expirationTime;
|
|
233
209
|
$newJwt = JWT::encode((array)$decodedToken, $this->secretKey, 'HS256');
|
|
234
210
|
|
|
@@ -244,13 +220,38 @@ class Auth
|
|
|
244
220
|
if (!headers_sent()) {
|
|
245
221
|
setcookie(self::$cookieName, $jwt, [
|
|
246
222
|
'expires' => $expirationTime,
|
|
247
|
-
'path' => '/',
|
|
248
|
-
'domain' => '',
|
|
249
|
-
'secure' => true,
|
|
250
|
-
'httponly' => true,
|
|
251
|
-
'samesite' => 'Lax',
|
|
223
|
+
'path' => '/',
|
|
224
|
+
'domain' => '',
|
|
225
|
+
'secure' => true,
|
|
226
|
+
'httponly' => true,
|
|
227
|
+
'samesite' => 'Lax',
|
|
228
|
+
]);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public function rotateCsrfToken(): void
|
|
233
|
+
{
|
|
234
|
+
$secret = $_ENV['FUNCTION_CALL_SECRET'] ?? '';
|
|
235
|
+
|
|
236
|
+
if (empty($secret)) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
$nonce = bin2hex(random_bytes(16));
|
|
241
|
+
$signature = hash_hmac('sha256', $nonce, $secret);
|
|
242
|
+
$token = $nonce . '.' . $signature;
|
|
243
|
+
|
|
244
|
+
if (!headers_sent()) {
|
|
245
|
+
setcookie('prisma_php_csrf', $token, [
|
|
246
|
+
'expires' => time() + 3600, // 1 hour validity
|
|
247
|
+
'path' => '/',
|
|
248
|
+
'secure' => true,
|
|
249
|
+
'httponly' => false, // Must be FALSE so client JS can read it
|
|
250
|
+
'samesite' => 'Lax',
|
|
252
251
|
]);
|
|
253
252
|
}
|
|
253
|
+
|
|
254
|
+
$_COOKIE['prisma_php_csrf'] = $token;
|
|
254
255
|
}
|
|
255
256
|
|
|
256
257
|
/**
|
|
@@ -276,6 +277,8 @@ class Auth
|
|
|
276
277
|
unset($_SESSION[self::PAYLOAD_SESSION_KEY]);
|
|
277
278
|
}
|
|
278
279
|
|
|
280
|
+
$this->rotateCsrfToken();
|
|
281
|
+
|
|
279
282
|
if ($redirect) {
|
|
280
283
|
Request::redirect($redirect);
|
|
281
284
|
}
|
package/dist/src/app/index.php
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<ol class="list-inside list-decimal text-sm/6 text-center sm:text-left">
|
|
9
9
|
<li class="mb-2 tracking-[-.01em]">
|
|
10
10
|
Get started by editing
|
|
11
|
-
<code class="bg-text-foreground/[.05] dark:bg-white/
|
|
11
|
+
<code class="bg-text-foreground/[.05] dark:bg-white/6 px-1 py-0.5 rounded font-semibold">
|
|
12
12
|
src/app/index.php
|
|
13
13
|
</code>
|
|
14
14
|
.
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
</div>
|
|
47
47
|
</main>
|
|
48
48
|
|
|
49
|
-
<footer class="row-start-3 flex gap-
|
|
49
|
+
<footer class="row-start-3 flex gap-6 flex-wrap items-center justify-center">
|
|
50
50
|
<a
|
|
51
51
|
class="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
52
52
|
href="https://prismaphp.tsnc.tech/docs?doc=learning-path"
|
package/dist/src/app/layout.php
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<?php
|
|
2
2
|
|
|
3
3
|
use PP\MainLayout;
|
|
4
|
-
use PP\Request;
|
|
5
4
|
|
|
6
5
|
MainLayout::$title = !empty(MainLayout::$title) ? MainLayout::$title : 'Create Prisma PHP App';
|
|
7
6
|
MainLayout::$description = !empty(MainLayout::$description) ? MainLayout::$description : 'Generated by create Prisma PHP App';
|
|
@@ -16,7 +15,7 @@ MainLayout::$description = !empty(MainLayout::$description) ? MainLayout::$descr
|
|
|
16
15
|
<!-- Dynamic Header Scripts -->
|
|
17
16
|
</head>
|
|
18
17
|
|
|
19
|
-
<body>
|
|
18
|
+
<body pp-spa="true" style="opacity:0;pointer-events:none;user-select:none;transition:opacity .18s ease-out;">
|
|
20
19
|
<?= MainLayout::$children; ?>
|
|
21
20
|
<!-- Dynamic Footer Scripts -->
|
|
22
21
|
</body>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
<div class="flex flex-col min-h-
|
|
1
|
+
<div class="flex flex-col min-h-screen items-center justify-center space-y-4 text-center">
|
|
2
2
|
<div class="space-y-2">
|
|
3
3
|
<h1 class="text-4xl font-bold tracking-tighter sm:text-5xl md:text-6xl">404 Not Found</h1>
|
|
4
|
-
<p class="max-w-
|
|
4
|
+
<p class="max-w-150 text-gray-500 md:text-xl/relaxed lg:text-base/relaxed xl:text-xl/relaxed dark:text-gray-400">
|
|
5
5
|
Sorry, we couldn't find the page you're looking for.
|
|
6
6
|
</p>
|
|
7
7
|
</div>
|
package/dist/tsconfig.json
CHANGED
|
@@ -106,6 +106,6 @@
|
|
|
106
106
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
|
107
107
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
|
108
108
|
},
|
|
109
|
-
|
|
109
|
+
"include": ["**/*.ts", ".pp/**/*.d.ts"],
|
|
110
110
|
"exclude": ["node_modules", "vendor"]
|
|
111
111
|
}
|
package/dist/vite.config.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { defineConfig, Plugin } from "vite";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import fg from "fast-glob";
|
|
4
4
|
import { writeFileSync } from "fs";
|
|
5
|
+
import { generateGlobalTypes } from "./settings/vite-plugins/generate-global-types.js";
|
|
5
6
|
|
|
6
7
|
const entries = Object.fromEntries(
|
|
7
8
|
fg.sync("ts/**/*.ts", { ignore: ["**/*.test.ts"] }).map((f) => {
|
|
@@ -10,6 +11,13 @@ const entries = Object.fromEntries(
|
|
|
10
11
|
})
|
|
11
12
|
);
|
|
12
13
|
|
|
14
|
+
const VITE_WATCH_EXCLUDE = [
|
|
15
|
+
"public/js/**",
|
|
16
|
+
"node_modules/**",
|
|
17
|
+
"vendor/**",
|
|
18
|
+
".pp/**",
|
|
19
|
+
];
|
|
20
|
+
|
|
13
21
|
function browserSyncNotify(): Plugin {
|
|
14
22
|
const flagFile = path.resolve(__dirname, ".pp", ".vite-build-complete");
|
|
15
23
|
|
|
@@ -21,16 +29,17 @@ function browserSyncNotify(): Plugin {
|
|
|
21
29
|
};
|
|
22
30
|
}
|
|
23
31
|
|
|
24
|
-
export default defineConfig({
|
|
32
|
+
export default defineConfig(({ command, mode }) => ({
|
|
25
33
|
publicDir: false,
|
|
26
34
|
build: {
|
|
27
35
|
outDir: "public/js",
|
|
28
36
|
emptyOutDir: false,
|
|
29
37
|
minify: "esbuild",
|
|
30
38
|
sourcemap: false,
|
|
31
|
-
watch:
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
watch:
|
|
40
|
+
command === "build" && mode === "development"
|
|
41
|
+
? { exclude: VITE_WATCH_EXCLUDE }
|
|
42
|
+
: undefined,
|
|
34
43
|
rollupOptions: {
|
|
35
44
|
input: entries,
|
|
36
45
|
external: [/^\/js\/.*/],
|
|
@@ -41,7 +50,12 @@ export default defineConfig({
|
|
|
41
50
|
},
|
|
42
51
|
},
|
|
43
52
|
},
|
|
44
|
-
plugins: [
|
|
53
|
+
plugins: [
|
|
54
|
+
generateGlobalTypes(),
|
|
55
|
+
...(command === "build" && mode === "development"
|
|
56
|
+
? [browserSyncNotify()]
|
|
57
|
+
: []),
|
|
58
|
+
],
|
|
45
59
|
esbuild: { legalComments: "none" },
|
|
46
60
|
define: { "process.env.NODE_ENV": '"production"' },
|
|
47
|
-
});
|
|
61
|
+
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-prisma-php-app",
|
|
3
|
-
"version": "4.2.2
|
|
3
|
+
"version": "4.2.2",
|
|
4
4
|
"description": "Prisma-PHP: A Revolutionary Library Bridging PHP with Prisma ORM",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,15 +32,15 @@
|
|
|
32
32
|
"author": "Jefferson Abraham Omier <thesteelninjacode@gmail.com>",
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"chalk": "^5.
|
|
35
|
+
"chalk": "^5.6.2",
|
|
36
36
|
"crypto-js": "^4.2.0",
|
|
37
37
|
"prompts": "^2.4.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/crypto-js": "^4.2.2",
|
|
41
|
-
"@types/node": "^
|
|
41
|
+
"@types/node": "^25.0.3",
|
|
42
42
|
"@types/prompts": "^2.4.9",
|
|
43
43
|
"ts-node": "^10.9.2",
|
|
44
|
-
"typescript": "^5.
|
|
44
|
+
"typescript": "^5.9.3"
|
|
45
45
|
}
|
|
46
46
|
}
|