@getstrata/starter 2.0.8 → 2.1.0
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/cli.js
CHANGED
|
@@ -2337,7 +2337,6 @@ function renderHomeView(projectName, layers) {
|
|
|
2337
2337
|
<a class="button" href="/register">Create account</a>
|
|
2338
2338
|
<a class="button button-secondary" href="/login">Sign in</a>
|
|
2339
2339
|
</div>
|
|
2340
|
-
<p class="muted">Seeded demo: <code>demo@example.com</code> / <code>StrataDemo!ChangeMe</code>.</p>
|
|
2341
2340
|
<% } else { %>
|
|
2342
2341
|
<p class="lede">You are signed in as <strong><%= it.currentUser.email %></strong>.</p>
|
|
2343
2342
|
<p>Add routes in <code>src/modules</code>. This homepage is yours to restyle.</p>
|
|
@@ -3192,9 +3191,9 @@ function renderPackageJson(projectName, options = {}) {
|
|
|
3192
3191
|
"@getstrata/cli": "workspace:*",
|
|
3193
3192
|
"@getstrata/core": "workspace:*"
|
|
3194
3193
|
} : {
|
|
3195
|
-
"@getstrata/bootstrap": "^2.0
|
|
3196
|
-
"@getstrata/cli": "^2.0
|
|
3197
|
-
"@getstrata/core": "^2.0
|
|
3194
|
+
"@getstrata/bootstrap": "^2.1.0",
|
|
3195
|
+
"@getstrata/cli": "^2.1.0",
|
|
3196
|
+
"@getstrata/core": "^2.1.0"
|
|
3198
3197
|
};
|
|
3199
3198
|
coreDeps.eta = "^4.6.0";
|
|
3200
3199
|
if (options.layers?.database === "mysql") {
|
|
@@ -3440,7 +3439,7 @@ function renderReadme(projectName, layers, options = {}) {
|
|
|
3440
3439
|
if (needsFrontendBuild(layers.frontend)) {
|
|
3441
3440
|
next.push("bun run frontend:install", "bun run frontend:build");
|
|
3442
3441
|
}
|
|
3443
|
-
next.push("bun run db:migrate", "bun run
|
|
3442
|
+
next.push("bun run db:migrate", "bun run dev");
|
|
3444
3443
|
const extras = Object.entries(layers.extras).filter(([, on]) => on).map(([key]) => key);
|
|
3445
3444
|
const dockerServices = selectedDockerServices(layers);
|
|
3446
3445
|
const neededTools = neededDockerServices(layers);
|
|
@@ -3474,7 +3473,7 @@ ${next.join(`
|
|
|
3474
3473
|
Open http://localhost:3000. Health check: \`GET /health\`. Redis worker: \`bun run queue:work\` (requires \`REDIS_URL\`).
|
|
3475
3474
|
|
|
3476
3475
|
${renderSupportingToolsReadme(layers)}${layers.auth !== "headers" ? `
|
|
3477
|
-
|
|
3476
|
+
Optional development demo accounts: run \`bun run db:seed:demo\` explicitly after migrations. This command refuses production and staging. It creates these accounts with password \`StrataDemo!ChangeMe\`:
|
|
3478
3477
|
|
|
3479
3478
|
- \`demo@example.com\` (member)
|
|
3480
3479
|
- \`admin@example.test\` (admin)
|
|
@@ -4048,12 +4047,6 @@ const notesTable = defineTable<NoteRecord, "id">({
|
|
|
4048
4047
|
defaultOrderBy: { column: "id", direction: "ASC" },
|
|
4049
4048
|
});
|
|
4050
4049
|
|
|
4051
|
-
class NoteRepository extends BaseRepository<NoteRecord, "id"> {
|
|
4052
|
-
constructor() {
|
|
4053
|
-
super(notesTable);
|
|
4054
|
-
}
|
|
4055
|
-
}
|
|
4056
|
-
|
|
4057
4050
|
class Note extends Model<NoteRecord, "id"> {
|
|
4058
4051
|
static $fillable = ${fillable} as const;
|
|
4059
4052
|
// created_at uses the table default. Sending a JS Date from $timestamps
|
|
@@ -4061,7 +4054,7 @@ class Note extends Model<NoteRecord, "id"> {
|
|
|
4061
4054
|
static $timestamps = false;
|
|
4062
4055
|
}
|
|
4063
4056
|
|
|
4064
|
-
registerModelRepository(Note, new
|
|
4057
|
+
registerModelRepository(Note, new BaseRepository(notesTable));
|
|
4065
4058
|
|
|
4066
4059
|
export type { NoteRecord };
|
|
4067
4060
|
export { Note };
|
|
@@ -4121,12 +4114,6 @@ const usersTable = defineTable<UserRecord, "id">({
|
|
|
4121
4114
|
defaultOrderBy: { column: "id", direction: "ASC" },
|
|
4122
4115
|
});
|
|
4123
4116
|
|
|
4124
|
-
class UserRepository extends BaseRepository<UserRecord, "id"> {
|
|
4125
|
-
constructor() {
|
|
4126
|
-
super(usersTable);
|
|
4127
|
-
}
|
|
4128
|
-
}
|
|
4129
|
-
|
|
4130
4117
|
class User extends Model<UserRecord, "id"> {
|
|
4131
4118
|
static $fillable = ${fillableLiteral} as const;
|
|
4132
4119
|
static $hidden = ${hiddenLiteral} as const;
|
|
@@ -4135,7 +4122,7 @@ class User extends Model<UserRecord, "id"> {
|
|
|
4135
4122
|
static $timestamps = false;
|
|
4136
4123
|
}
|
|
4137
4124
|
|
|
4138
|
-
registerModelRepository(User, new
|
|
4125
|
+
registerModelRepository(User, new BaseRepository(usersTable));
|
|
4139
4126
|
|
|
4140
4127
|
export type { UserRecord };
|
|
4141
4128
|
export { User };
|
|
@@ -4164,12 +4151,6 @@ const apiTokensTable = defineTable<ApiTokenRecord, "id">({
|
|
|
4164
4151
|
defaultOrderBy: { column: "id", direction: "ASC" },
|
|
4165
4152
|
});
|
|
4166
4153
|
|
|
4167
|
-
class ApiTokenRepository extends BaseRepository<ApiTokenRecord, "id"> {
|
|
4168
|
-
constructor() {
|
|
4169
|
-
super(apiTokensTable);
|
|
4170
|
-
}
|
|
4171
|
-
}
|
|
4172
|
-
|
|
4173
4154
|
class ApiToken extends Model<ApiTokenRecord, "id"> {
|
|
4174
4155
|
static $fillable = ["user_id", "name", "token_hash", "abilities", "expires_at", "last_used_at"] as const;
|
|
4175
4156
|
// created_at uses the table default. Sending a JS Date from $timestamps
|
|
@@ -4177,7 +4158,7 @@ class ApiToken extends Model<ApiTokenRecord, "id"> {
|
|
|
4177
4158
|
static $timestamps = false;
|
|
4178
4159
|
}
|
|
4179
4160
|
|
|
4180
|
-
registerModelRepository(ApiToken, new
|
|
4161
|
+
registerModelRepository(ApiToken, new BaseRepository(apiTokensTable));
|
|
4181
4162
|
|
|
4182
4163
|
export type { ApiTokenRecord };
|
|
4183
4164
|
export { ApiToken };
|
|
@@ -4204,18 +4185,12 @@ const authOneTimeTokensTable = defineTable<AuthOneTimeTokenRecord, "id">({
|
|
|
4204
4185
|
defaultOrderBy: { column: "id", direction: "ASC" },
|
|
4205
4186
|
});
|
|
4206
4187
|
|
|
4207
|
-
class AuthOneTimeTokenRepository extends BaseRepository<AuthOneTimeTokenRecord, "id"> {
|
|
4208
|
-
constructor() {
|
|
4209
|
-
super(authOneTimeTokensTable);
|
|
4210
|
-
}
|
|
4211
|
-
}
|
|
4212
|
-
|
|
4213
4188
|
class AuthOneTimeToken extends Model<AuthOneTimeTokenRecord, "id"> {
|
|
4214
4189
|
static $fillable = ["purpose", "user_id", "token_hash", "expires_at", "consumed_at"] as const;
|
|
4215
4190
|
static $timestamps = false;
|
|
4216
4191
|
}
|
|
4217
4192
|
|
|
4218
|
-
registerModelRepository(AuthOneTimeToken, new
|
|
4193
|
+
registerModelRepository(AuthOneTimeToken, new BaseRepository(authOneTimeTokensTable));
|
|
4219
4194
|
|
|
4220
4195
|
export type { AuthOneTimeTokenRecord };
|
|
4221
4196
|
export { AuthOneTimeToken };
|
|
@@ -4225,7 +4200,6 @@ function renderModelsRegister(layers) {
|
|
|
4225
4200
|
const lines = [
|
|
4226
4201
|
"// Side-effect imports run registerModelRepository() in each model file.",
|
|
4227
4202
|
"// registerModelClass() is only for a string alias that is neither constructor.name nor $morphClass.",
|
|
4228
|
-
'import { registerModelClass } from "@getstrata/core/database/model";',
|
|
4229
4203
|
'import "./Note.ts";'
|
|
4230
4204
|
];
|
|
4231
4205
|
if (authNeedsUsers(layers.auth)) {
|
|
@@ -4236,9 +4210,9 @@ function renderModelsRegister(layers) {
|
|
|
4236
4210
|
lines.push('import "./ApiToken.ts";');
|
|
4237
4211
|
}
|
|
4238
4212
|
lines.push("");
|
|
4239
|
-
lines.push("//
|
|
4240
|
-
lines.push('// registerModelClass
|
|
4241
|
-
lines.push(
|
|
4213
|
+
lines.push("// Optional alias when a relation uses belongsTo('CategoryAlias'):");
|
|
4214
|
+
lines.push('// import { registerModelClass } from "@getstrata/core/database/model";');
|
|
4215
|
+
lines.push('// registerModelClass("CategoryAlias", Category);');
|
|
4242
4216
|
lines.push("");
|
|
4243
4217
|
return `${lines.join(`
|
|
4244
4218
|
`)}
|
|
@@ -4614,10 +4588,9 @@ import "./preload.ts";
|
|
|
4614
4588
|
import { runProviderPhase } from "@getstrata/bootstrap/context";
|
|
4615
4589
|
import {
|
|
4616
4590
|
type AppContext,
|
|
4617
|
-
type AppDependencies,
|
|
4618
4591
|
type AppRouteMap,
|
|
4619
4592
|
assertAppDependenciesComplete,
|
|
4620
|
-
|
|
4593
|
+
ConfigStore,
|
|
4621
4594
|
type MutableAppDependencies,
|
|
4622
4595
|
type ProviderContext,
|
|
4623
4596
|
ServiceContainer,
|
|
@@ -4650,34 +4623,9 @@ export interface BootstrappedApp {
|
|
|
4650
4623
|
config: ReturnType<typeof loadConfig>;
|
|
4651
4624
|
}
|
|
4652
4625
|
|
|
4653
|
-
class AppConfigStore {
|
|
4654
|
-
private readonly values = new Map<string, unknown>();
|
|
4655
|
-
|
|
4656
|
-
set<T>(key: string, value: T): T {
|
|
4657
|
-
this.values.set(key, value);
|
|
4658
|
-
return value;
|
|
4659
|
-
}
|
|
4660
|
-
|
|
4661
|
-
get<T>(key: string): T | undefined {
|
|
4662
|
-
return this.values.get(key) as T | undefined;
|
|
4663
|
-
}
|
|
4664
|
-
|
|
4665
|
-
require<T>(key: string): T {
|
|
4666
|
-
const value = this.get<T>(key);
|
|
4667
|
-
if (value === undefined) {
|
|
4668
|
-
throw new Error(\`Missing required config value "\${key}".\`);
|
|
4669
|
-
}
|
|
4670
|
-
return value;
|
|
4671
|
-
}
|
|
4672
|
-
|
|
4673
|
-
has(key: string): boolean {
|
|
4674
|
-
return this.values.has(key);
|
|
4675
|
-
}
|
|
4676
|
-
}
|
|
4677
|
-
|
|
4678
4626
|
function createAppContext(): AppContext {
|
|
4679
4627
|
const container = new ServiceContainer();
|
|
4680
|
-
const config = new
|
|
4628
|
+
const config = new ConfigStore();
|
|
4681
4629
|
const dependencies: MutableAppDependencies = { container };
|
|
4682
4630
|
const context: ProviderContext = { container, config, dependencies };
|
|
4683
4631
|
|
|
@@ -4690,8 +4638,8 @@ function createAppContext(): AppContext {
|
|
|
4690
4638
|
|
|
4691
4639
|
assertAppDependenciesComplete(dependencies);
|
|
4692
4640
|
|
|
4693
|
-
const appContext = { container, config, dependencies
|
|
4694
|
-
setActiveApplicationContext(appContext
|
|
4641
|
+
const appContext: AppContext = { container, config, dependencies };
|
|
4642
|
+
setActiveApplicationContext(appContext);
|
|
4695
4643
|
return appContext;
|
|
4696
4644
|
}
|
|
4697
4645
|
|
|
@@ -6,8 +6,8 @@ import { useAuth } from "../auth/AuthContext";
|
|
|
6
6
|
export default function LoginPage() {
|
|
7
7
|
const { login, user } = useAuth();
|
|
8
8
|
const navigate = useNavigate();
|
|
9
|
-
const [email, setEmail] = useState("
|
|
10
|
-
const [password, setPassword] = useState("
|
|
9
|
+
const [email, setEmail] = useState("");
|
|
10
|
+
const [password, setPassword] = useState("");
|
|
11
11
|
const [error, setError] = useState<string | null>(null);
|
|
12
12
|
const [submitting, setSubmitting] = useState(false);
|
|
13
13
|
|
|
@@ -33,10 +33,7 @@ export default function LoginPage() {
|
|
|
33
33
|
return (
|
|
34
34
|
<section className="card">
|
|
35
35
|
<h1>Sign in</h1>
|
|
36
|
-
<p className="hint">
|
|
37
|
-
Seeded users are <code>demo@example.com</code> and <code>admin@example.test</code>, password
|
|
38
|
-
<code>StrataDemo!ChangeMe</code>.
|
|
39
|
-
</p>
|
|
36
|
+
<p className="hint">Enter your account email and password.</p>
|
|
40
37
|
|
|
41
38
|
{error ? <p className="error">{error}</p> : null}
|
|
42
39
|
|
|
@@ -45,6 +42,8 @@ export default function LoginPage() {
|
|
|
45
42
|
Email
|
|
46
43
|
<input
|
|
47
44
|
type="email"
|
|
45
|
+
name="email"
|
|
46
|
+
autoComplete="username"
|
|
48
47
|
value={email}
|
|
49
48
|
onChange={(event) => setEmail(event.target.value)}
|
|
50
49
|
required
|
|
@@ -55,6 +54,8 @@ export default function LoginPage() {
|
|
|
55
54
|
Password
|
|
56
55
|
<input
|
|
57
56
|
type="password"
|
|
57
|
+
name="password"
|
|
58
|
+
autoComplete="current-password"
|
|
58
59
|
value={password}
|
|
59
60
|
onChange={(event) => setPassword(event.target.value)}
|
|
60
61
|
required
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
"check": "tsc --noEmit"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@getstrata/bootstrap": "^2.0
|
|
16
|
-
"@getstrata/cli": "^2.0
|
|
17
|
-
"@getstrata/core": "^2.0
|
|
15
|
+
"@getstrata/bootstrap": "^2.1.0",
|
|
16
|
+
"@getstrata/cli": "^2.1.0",
|
|
17
|
+
"@getstrata/core": "^2.1.0",
|
|
18
18
|
"eta": "^4.6.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|