@storyshelf/auth 0.6.0 → 0.6.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/bootstrap.mjs +3 -0
- package/dist/bootstrap.mjs.map +1 -1
- package/package.json +4 -4
package/dist/bootstrap.mjs
CHANGED
|
@@ -5,6 +5,8 @@ import { ensureEngineIdentity, tableColumn } from "./invites.mjs";
|
|
|
5
5
|
import { eq } from "@storyshelf/core/orm";
|
|
6
6
|
import { ulid } from "@storyshelf/core/utils";
|
|
7
7
|
//#region src/bootstrap.ts
|
|
8
|
+
/** Matches what Better Auth accepts at sign-in: the domain needs a dot. */
|
|
9
|
+
const ENGINE_EMAIL = /^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/u;
|
|
8
10
|
/** Find the env admin row, or stage it (admin role, no credential yet). */
|
|
9
11
|
async function stagePasswordAdmin(db, email, name, now) {
|
|
10
12
|
const existing = (await db.list(db.tables.users, {
|
|
@@ -29,6 +31,7 @@ async function stagePasswordAdmin(db, email, name, now) {
|
|
|
29
31
|
/** Provision (or refresh the credential of) the env-driven local admin. */
|
|
30
32
|
async function ensurePasswordAdmin(db, input) {
|
|
31
33
|
const email = input.email.trim().toLowerCase();
|
|
34
|
+
if (!ENGINE_EMAIL.test(email)) throw new Error(`AUTH_EMAIL "${email}" is not a valid email address (domain needs a dot)`);
|
|
32
35
|
if (input.password.length < 12) throw new Error("Password must be at least 12 characters");
|
|
33
36
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
34
37
|
const shelfUser = await stagePasswordAdmin(db, email, input.name ?? "Admin", now);
|
package/dist/bootstrap.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.mjs","names":[],"sources":["../src/bootstrap.ts"],"sourcesContent":["/**\n * Development bootstrap: provision a local admin from environment credentials.\n *\n * Replaces the dropped shared-password tier for `dev-server`/`fly-app`:\n * with `AUTH_PASSWORD` set, the first boot creates an admin identity and\n * every boot aligns its engine credential with the env value (same\n * always-from-env semantics the shared tier had). Production deployments\n * use the invite flow instead.\n */\nimport type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { eq } from \"@storyshelf/core/orm\";\nimport { ulid } from \"@storyshelf/core/utils\";\nimport { ensureEngineIdentity, MIN_PASSWORD_LENGTH, tableColumn } from \"./invites.ts\";\n\n/** Input for {@link ensurePasswordAdmin}. */\nexport interface PasswordAdminInput {\n email: string;\n name?: string;\n password: string;\n}\n\n/** Find the env admin row, or stage it (admin role, no credential yet). */\nasync function stagePasswordAdmin(\n db: DatabaseAdapter,\n email: string,\n name: string,\n now: string,\n): Promise<Record<string, unknown>> {\n const rows: Record<string, unknown>[] = await db.list(db.tables.users, {\n where: eq(tableColumn(db.tables.users, \"email\"), email),\n limit: 1,\n });\n const existing = rows[0];\n if (existing) {\n return existing;\n }\n return await db.insert(db.tables.users, {\n id: ulid(),\n email,\n name,\n avatarUrl: null,\n role: \"admin\",\n lastLoginAt: null,\n createdAt: now,\n passwordHash: null,\n displayNameOverride: null,\n authProvider: \"local\",\n disabled: false,\n });\n}\n\n/** Provision (or refresh the credential of) the env-driven local admin. */\nexport async function ensurePasswordAdmin(\n db: DatabaseAdapter,\n input: PasswordAdminInput,\n): Promise<void> {\n const email = input.email.trim().toLowerCase();\n if (input.password.length < MIN_PASSWORD_LENGTH) {\n throw new Error(\"Password must be at least 12 characters\");\n }\n const now = new Date().toISOString();\n const shelfUser = await stagePasswordAdmin(db, email, input.name ?? \"Admin\", now);\n await ensureEngineIdentity(db, shelfUser, input.password);\n}\n"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"bootstrap.mjs","names":[],"sources":["../src/bootstrap.ts"],"sourcesContent":["/**\n * Development bootstrap: provision a local admin from environment credentials.\n *\n * Replaces the dropped shared-password tier for `dev-server`/`fly-app`:\n * with `AUTH_PASSWORD` set, the first boot creates an admin identity and\n * every boot aligns its engine credential with the env value (same\n * always-from-env semantics the shared tier had). Production deployments\n * use the invite flow instead.\n */\nimport type { DatabaseAdapter } from \"@storyshelf/core/adapter/database\";\nimport { eq } from \"@storyshelf/core/orm\";\nimport { ulid } from \"@storyshelf/core/utils\";\nimport { ensureEngineIdentity, MIN_PASSWORD_LENGTH, tableColumn } from \"./invites.ts\";\n\n/** Matches what Better Auth accepts at sign-in: the domain needs a dot. */\nconst ENGINE_EMAIL = /^[^\\s@]+@[^\\s@.]+(?:\\.[^\\s@.]+)+$/u;\n\n/** Input for {@link ensurePasswordAdmin}. */\nexport interface PasswordAdminInput {\n email: string;\n name?: string;\n password: string;\n}\n\n/** Find the env admin row, or stage it (admin role, no credential yet). */\nasync function stagePasswordAdmin(\n db: DatabaseAdapter,\n email: string,\n name: string,\n now: string,\n): Promise<Record<string, unknown>> {\n const rows: Record<string, unknown>[] = await db.list(db.tables.users, {\n where: eq(tableColumn(db.tables.users, \"email\"), email),\n limit: 1,\n });\n const existing = rows[0];\n if (existing) {\n return existing;\n }\n return await db.insert(db.tables.users, {\n id: ulid(),\n email,\n name,\n avatarUrl: null,\n role: \"admin\",\n lastLoginAt: null,\n createdAt: now,\n passwordHash: null,\n displayNameOverride: null,\n authProvider: \"local\",\n disabled: false,\n });\n}\n\n/** Provision (or refresh the credential of) the env-driven local admin. */\nexport async function ensurePasswordAdmin(\n db: DatabaseAdapter,\n input: PasswordAdminInput,\n): Promise<void> {\n const email = input.email.trim().toLowerCase();\n if (!ENGINE_EMAIL.test(email)) {\n // The engine rejects dotless domains (e.g. admin@local) at sign-in, so the account could never log in.\n throw new Error(`AUTH_EMAIL \"${email}\" is not a valid email address (domain needs a dot)`);\n }\n if (input.password.length < MIN_PASSWORD_LENGTH) {\n throw new Error(\"Password must be at least 12 characters\");\n }\n const now = new Date().toISOString();\n const shelfUser = await stagePasswordAdmin(db, email, input.name ?? \"Admin\", now);\n await ensureEngineIdentity(db, shelfUser, input.password);\n}\n"],"mappings":";;;;;;;;AAeA,MAAM,eAAe;;AAUrB,eAAe,mBACb,IACA,OACA,MACA,KACkC;CAKlC,MAAM,YAAW,MAJ6B,GAAG,KAAK,GAAG,OAAO,OAAO;EACrE,OAAO,GAAG,YAAY,GAAG,OAAO,OAAO,OAAO,GAAG,KAAK;EACtD,OAAO;CACT,CAAC,EAAA,CACqB;CACtB,IAAI,UACF,OAAO;CAET,OAAO,MAAM,GAAG,OAAO,GAAG,OAAO,OAAO;EACtC,IAAI,KAAK;EACT;EACA;EACA,WAAW;EACX,MAAM;EACN,aAAa;EACb,WAAW;EACX,cAAc;EACd,qBAAqB;EACrB,cAAc;EACd,UAAU;CACZ,CAAC;AACH;;AAGA,eAAsB,oBACpB,IACA,OACe;CACf,MAAM,QAAQ,MAAM,MAAM,KAAK,CAAC,CAAC,YAAY;CAC7C,IAAI,CAAC,aAAa,KAAK,KAAK,GAE1B,MAAM,IAAI,MAAM,eAAe,MAAM,oDAAoD;CAE3F,IAAI,MAAM,SAAS,SAAA,IACjB,MAAM,IAAI,MAAM,yCAAyC;CAE3D,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;CACnC,MAAM,YAAY,MAAM,mBAAmB,IAAI,OAAO,MAAM,QAAQ,SAAS,GAAG;CAChF,MAAM,qBAAqB,IAAI,WAAW,MAAM,QAAQ;AAC1D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storyshelf/auth",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Better Auth engine for StoryShelf: opaque DBAdapter bridge, shelf factory, and auth presets.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"auth",
|
|
@@ -53,13 +53,13 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@better-auth/passkey": "1.7.6",
|
|
55
55
|
"@better-auth/sso": "1.7.6",
|
|
56
|
-
"@storyshelf/core": "0.6.
|
|
56
|
+
"@storyshelf/core": "0.6.1",
|
|
57
57
|
"better-auth": "1.7.6",
|
|
58
58
|
"zod": "^4.2.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@storyshelf/db-postgres": "0.6.
|
|
62
|
-
"@storyshelf/db-sqlite": "0.6.
|
|
61
|
+
"@storyshelf/db-postgres": "0.6.1",
|
|
62
|
+
"@storyshelf/db-sqlite": "0.6.1",
|
|
63
63
|
"@types/node": "^26.0.0",
|
|
64
64
|
"@vitest/coverage-v8": "^4.0.0",
|
|
65
65
|
"oxfmt": "^0.65.0",
|