@sedim/cli 1.0.1 → 1.0.3

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/index.js CHANGED
@@ -10,7 +10,7 @@ var __export = (target, all) => {
10
10
  };
11
11
 
12
12
  // src/shared/constants.ts
13
- var SEDIM_DIR, SEDIM_CONFIG_FILE, SEDIM_CONFIG_CACHE, SEDIM_SESSION_FILE, SEDIM_MODULES_DIR, SEDIM_LOGS_DIR, SEDIM_LATEST_LOG, DEFAULT_REGISTRY_URL, MIN_NODE_VERSION, CLI_VERSION;
13
+ var SEDIM_DIR, SEDIM_CONFIG_FILE, SEDIM_CONFIG_CACHE, SEDIM_SESSION_FILE, SEDIM_MODULES_DIR, SEDIM_LOGS_DIR, SEDIM_LATEST_LOG, DEFAULT_REGISTRY_URL, DEFAULT_PACKAGES_URL, MIN_NODE_VERSION, CLI_VERSION;
14
14
  var init_constants = __esm({
15
15
  "src/shared/constants.ts"() {
16
16
  "use strict";
@@ -22,8 +22,9 @@ var init_constants = __esm({
22
22
  SEDIM_LOGS_DIR = `${SEDIM_DIR}/logs`;
23
23
  SEDIM_LATEST_LOG = `${SEDIM_LOGS_DIR}/latest.log`;
24
24
  DEFAULT_REGISTRY_URL = "https://raw.githubusercontent.com/sedimie/Sedim/main/registry";
25
+ DEFAULT_PACKAGES_URL = "https://raw.githubusercontent.com/sedimie/Sedim/main/packages";
25
26
  MIN_NODE_VERSION = 18;
26
- CLI_VERSION = "1.0.0";
27
+ CLI_VERSION = "1.0.3";
27
28
  }
28
29
  });
29
30
 
@@ -4254,26 +4255,16 @@ async function classifyConflicts(projectRoot, ctx, filesToCreate, schemaTables)
4254
4255
  }
4255
4256
 
4256
4257
  // src/thinker/resolve-template.ts
4257
- init_fs();
4258
+ init_constants();
4258
4259
  import path23 from "path";
4259
4260
  import { fileURLToPath as fileURLToPath3 } from "url";
4260
- import { existsSync } from "fs";
4261
4261
  var __dirname3 = path23.dirname(fileURLToPath3(import.meta.url));
4262
- function getPackageRoot(projectRoot, moduleName) {
4263
- return path23.resolve(projectRoot, "..", "..", "..", "packages", moduleName, "src");
4264
- }
4265
- async function resolveTemplate(templateKey, ctx, selectedFeatures = []) {
4262
+ async function resolveTemplate(templateKey, ctx, selectedFeatures = [], packagesUrl = DEFAULT_PACKAGES_URL) {
4266
4263
  const [moduleName, ...rest] = templateKey.split("/");
4267
4264
  if (!moduleName || rest.length === 0) {
4268
4265
  throw new Error(`Invalid templateKey: "${templateKey}"`);
4269
4266
  }
4270
4267
  const relPath = rest.join("/");
4271
- const projectRoot = ctx.projectRoot ?? process.cwd();
4272
- const packageRoot = getPackageRoot(projectRoot, moduleName);
4273
- const tryPackageRoot = (levels) => path23.resolve(__dirname3, levels, "packages", moduleName, "src");
4274
- const packageRoot3 = tryPackageRoot("../../..");
4275
- const packageRoot4 = tryPackageRoot("../../../../..");
4276
- const resolvedRoot = existsSync(packageRoot) ? packageRoot : existsSync(packageRoot3) ? packageRoot3 : existsSync(packageRoot4) ? packageRoot4 : packageRoot;
4277
4268
  const generatedKeys = {
4278
4269
  "ui/pages/login-page": (f) => buildLoginPage(f),
4279
4270
  "ui/pages/signup-page": (f) => buildSignupPage(f),
@@ -4285,58 +4276,60 @@ async function resolveTemplate(templateKey, ctx, selectedFeatures = []) {
4285
4276
  return generatedKeys[relPath](selectedFeatures, ctx);
4286
4277
  }
4287
4278
  let content;
4288
- const templatePath = path23.join(resolvedRoot, "templates", `${relPath}.ts`);
4289
- if (await exists(templatePath)) {
4290
- const raw = await readText(templatePath);
4291
- content = applySubstitutions(raw, ctx, selectedFeatures);
4279
+ let found = false;
4280
+ const asIsUrl = `${packagesUrl}/${moduleName}/src/${relPath}`;
4281
+ const asIsFetched = await tryFetch(asIsUrl);
4282
+ if (asIsFetched !== null) {
4283
+ content = asIsFetched;
4284
+ found = true;
4292
4285
  } else {
4293
- const templatePrismaPath = path23.join(resolvedRoot, "templates", `${relPath}.prisma`);
4294
- if (await exists(templatePrismaPath)) {
4295
- const raw = await readText(templatePrismaPath);
4296
- content = applySubstitutions(raw, ctx, selectedFeatures);
4286
+ for (const tryExt of ["ts", "tsx", "css", "prisma"]) {
4287
+ const url = `${packagesUrl}/${moduleName}/src/${relPath}.${tryExt}`;
4288
+ const raw = await tryFetch(url);
4289
+ if (raw !== null) {
4290
+ content = raw;
4291
+ found = true;
4292
+ break;
4293
+ }
4294
+ }
4295
+ }
4296
+ if (!found) {
4297
+ const templateAsIs = `${packagesUrl}/${moduleName}/src/templates/${relPath}`;
4298
+ const fetchedAsIs = await tryFetch(templateAsIs);
4299
+ if (fetchedAsIs !== null) {
4300
+ content = fetchedAsIs;
4301
+ found = true;
4297
4302
  } else {
4298
- const knownExts = [".ts", ".tsx", ".css", ".prisma"];
4299
- const hasExt = knownExts.some((e) => relPath.endsWith(e));
4300
- if (hasExt) {
4301
- const sourcePath = path23.join(resolvedRoot, relPath);
4302
- if (await exists(sourcePath)) {
4303
- content = await readText(sourcePath);
4304
- content = applySubstitutions(content, ctx, selectedFeatures);
4305
- } else {
4306
- content = "";
4307
- }
4308
- } else {
4309
- let found = false;
4310
- content = "";
4311
- for (const ext of [".ts", ".tsx", ".css"]) {
4312
- const sourcePath = path23.join(resolvedRoot, `${relPath}${ext}`);
4313
- if (await exists(sourcePath)) {
4314
- const raw = await readText(sourcePath);
4315
- content = applySubstitutions(raw, ctx, selectedFeatures);
4316
- found = true;
4317
- break;
4318
- }
4319
- }
4320
- if (!found) {
4321
- const sourcePrismaPath = path23.join(resolvedRoot, `${relPath}.prisma`);
4322
- if (await exists(sourcePrismaPath)) {
4323
- content = await readText(sourcePrismaPath);
4324
- } else {
4325
- throw new Error(
4326
- `Template not found for key "${templateKey}". Checked:
4327
- ${templatePath}
4328
- ${path23.join(resolvedRoot, relPath)}.[ts|tsx|css]`
4329
- );
4330
- }
4331
- }
4303
+ const templateUrl = `${packagesUrl}/${moduleName}/src/templates/${relPath}.ts`;
4304
+ const fetched = await tryFetch(templateUrl);
4305
+ if (fetched !== null) {
4306
+ content = fetched;
4307
+ found = true;
4332
4308
  }
4333
4309
  }
4334
4310
  }
4311
+ if (!found) {
4312
+ throw new Error(
4313
+ `Template not found for key "${templateKey}". Checked:
4314
+ ${packagesUrl}/${moduleName}/src/${relPath}.[ts|tsx|css|prisma]
4315
+ ${packagesUrl}/${moduleName}/src/templates/${relPath}.ts`
4316
+ );
4317
+ }
4318
+ content = applySubstitutions(content, ctx, selectedFeatures);
4335
4319
  if (!relPath.endsWith(".css") && !relPath.endsWith(".prisma")) {
4336
4320
  content = stripRelativeJsExtensions(content);
4337
4321
  }
4338
4322
  return content;
4339
4323
  }
4324
+ async function tryFetch(url) {
4325
+ try {
4326
+ const res = await fetch(url);
4327
+ if (!res.ok) return null;
4328
+ return res.text();
4329
+ } catch {
4330
+ return null;
4331
+ }
4332
+ }
4340
4333
  function stripRelativeJsExtensions(content) {
4341
4334
  return content.replace(/(from\s+['"])(\.\.?\/[^'"]*?)\.js(['"])/g, "$1$2$3");
4342
4335
  }
@@ -4411,7 +4404,7 @@ function buildProvidersImport(features) {
4411
4404
  if (features.includes("oauth-github")) providerFns.push("githubProvider");
4412
4405
  if (features.includes("oauth-discord")) providerFns.push("discordProvider");
4413
4406
  if (providerFns.length === 0) return "";
4414
- return `import { ${providerFns.join(", ")} } from './adapters/framework-config.js'`;
4407
+ return `import { ${providerFns.join(", ")} } from './adapters/framework/framework-config.js'`;
4415
4408
  }
4416
4409
  function buildProvidersConfig(features) {
4417
4410
  const lines = [];
@@ -4475,7 +4468,7 @@ function buildLoginPage(features) {
4475
4468
  ` <p style={{ textAlign: 'center', fontSize: '0.8125rem', color: '${mutedColor}', margin: 0 }}>`
4476
4469
  );
4477
4470
  body.push(
4478
- ` Don&apos;t have an account?{' '}<a href="/signup" style={{ color: '${fgColor}', fontWeight: 600, textDecoration: 'none' }}>Sign up</a>`
4471
+ ` Don't have an account?{' '}<a href="/signup" style={{ color: '${fgColor}', fontWeight: 600, textDecoration: 'none' }}>Sign up</a>`
4479
4472
  );
4480
4473
  body.push(` </p>`);
4481
4474
  }
@@ -4640,7 +4633,7 @@ function buildForgotPage(features = []) {
4640
4633
  const inner = [
4641
4634
  ` <div style={{ textAlign: 'center' }}>`,
4642
4635
  ` <h1 style={{ fontSize: '1.5rem', fontWeight: 700, margin: '0 0 0.25rem' }}>Reset password</h1>`,
4643
- ` <p style={{ fontSize: '0.875rem', color: '${mutedColor}', margin: 0 }}>Enter your email and we&apos;ll send a reset link.</p>`,
4636
+ ` <p style={{ fontSize: '0.875rem', color: '${mutedColor}', margin: 0 }}>Enter your email and we'll send a reset link.</p>`,
4644
4637
  ` </div>`,
4645
4638
  ` <ForgotPasswordForm />`,
4646
4639
  ` <p style={{ textAlign: 'center', fontSize: '0.8125rem', margin: 0 }}>`,
@@ -5017,7 +5010,31 @@ function manifestToPlanConfig(manifest, selectedFeatures, _ctx) {
5017
5010
  }
5018
5011
 
5019
5012
  // src/thinker/load-plan-config.ts
5020
- async function loadPlanConfig(moduleName, manifest, ctx, selectedFeatures) {
5013
+ init_constants();
5014
+ import { createWriteStream } from "fs";
5015
+ import https from "https";
5016
+ import os from "os";
5017
+ import { pipeline } from "stream";
5018
+ import { promisify } from "util";
5019
+ var streamPipeline = promisify(pipeline);
5020
+ async function downloadToTemp(url, suffix) {
5021
+ const tmpDir = os.tmpdir();
5022
+ const tmpPath = `${tmpDir}/sedim-${suffix}-${Date.now()}.js`;
5023
+ await new Promise((resolve, reject) => {
5024
+ const req = https.get(url, (res) => {
5025
+ if (res.statusCode !== 200) {
5026
+ reject(new Error(`HTTP ${res.statusCode}`));
5027
+ return;
5028
+ }
5029
+ const file = createWriteStream(tmpPath);
5030
+ res.pipe(file);
5031
+ file.on("finish", () => file.close(() => resolve()));
5032
+ });
5033
+ req.on("error", reject);
5034
+ });
5035
+ return tmpPath;
5036
+ }
5037
+ async function loadPlanConfig(moduleName, manifest, ctx, selectedFeatures, packagesUrl = DEFAULT_PACKAGES_URL) {
5021
5038
  try {
5022
5039
  const fnName = `create${capitalize(moduleName)}PlanConfig`;
5023
5040
  const mod = await import(`@sedim/${moduleName}/plan-config`);
@@ -5027,7 +5044,20 @@ async function loadPlanConfig(moduleName, manifest, ctx, selectedFeatures) {
5027
5044
  selectedFeatures
5028
5045
  );
5029
5046
  }
5030
- } catch (err) {
5047
+ } catch {
5048
+ }
5049
+ try {
5050
+ const fnName = `create${capitalize(moduleName)}PlanConfig`;
5051
+ const remoteUrl = `${packagesUrl}/${moduleName}/planConfig/plan-config.js`;
5052
+ const tmpPath = await downloadToTemp(remoteUrl, moduleName);
5053
+ const mod = await import(tmpPath);
5054
+ if (mod && typeof mod[fnName] === "function") {
5055
+ return mod[fnName](
5056
+ ctx,
5057
+ selectedFeatures
5058
+ );
5059
+ }
5060
+ } catch {
5031
5061
  }
5032
5062
  return manifestToPlanConfig(manifest, selectedFeatures, ctx);
5033
5063
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sedim/cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Premium codegen CLI — stamp production-ready feature modules into your project",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/CONTRIBUTING.md DELETED
@@ -1,385 +0,0 @@
1
- # Contributing to Sedim
2
-
3
- Thank you for wanting to contribute. This guide explains everything you need to know to work on the Sedim codebase.
4
-
5
- ---
6
-
7
- To start off, you'll need an overview of what's happening in the library, so first going through the readme in full is recommended. Post that, let's try to understand the architecture of the whole library a bit.
8
-
9
- This is a monorepo, with packages as the `core`, `cli`, `auth`, and other modules to be added in the future.
10
- `core` contains the shared types between the `cli` and any `module`. The `cli` is built such that any module can seemlessly fit into it and give the same experience to the user.
11
-
12
-
13
-
14
- ## What can you contribute?
15
-
16
- There are lots of ways to help, no matter your experience level:
17
-
18
- - **Bug reports and bug fixes** - something is broken, you know how to fix it
19
- - **New features** - a framework adapter, an ORM adapter, a new module
20
- - **Feature additions under an existing module** - more auth providers, more UI components, more email transports
21
- - **UI/UX improvements** - accessibility fixes, better form states, new theme variants
22
- - **Documentation** - fixing broken links, clarifying confusing sections, writing guides
23
- - **Feature requests** - you want something that does not exist yet
24
- - **Testing** - adding tests to existing modules, testing on different platforms
25
- - **Design** - helping design better auth UI components, visual refinements
26
-
27
- If you're unsure whether something is worth contributing, just open an issue. We'd rather you ask than guess.
28
-
29
- ---
30
-
31
- ## Getting Started
32
-
33
- ### What you need
34
-
35
- - **Node.js 18+**
36
- - **pnpm 9+**
37
-
38
- ### Set up the project
39
-
40
- ```bash
41
- git clone https://github.com/Sedimie/Sedim.git
42
- cd Sedim
43
- pnpm install
44
- pnpm build
45
- ```
46
-
47
- ### Run tests
48
-
49
- ```bash
50
- pnpm test # all packages
51
- pnpm --filter @sedim/auth test # auth module only
52
- pnpm --filter @sedim/cli test # CLI only
53
- ```
54
-
55
- ---
56
-
57
- ## Project Structure
58
-
59
- ```
60
- Sedim/
61
- ├── packages/
62
- │ ├── auth/ — the auth module (v0.2.0)
63
- │ ├── cli/ — the Sedim CLI engine
64
- │ └── core/ — shared types used by CLI and modules
65
- ├── apps/
66
- │ ├── playground/ — fixture apps for testing
67
- │ └── docs/ — VitePress documentation site
68
- └── registry/
69
- └── auth/latest.json — module manifest
70
- ```
71
-
72
- ---
73
-
74
- ## Where things live
75
-
76
- | Directory | What it is |
77
- |----------|------------|
78
- | `packages/auth/src/core/` | Auth logic: hashing, sessions, tokens, PKCE, TOTP, RBAC, ABAC, JWT, email |
79
- | `packages/auth/src/adapters/framework/` | Framework adapters: Next.js, Express, Hono |
80
- | `packages/auth/src/adapters/` | ORM adapters: Drizzle, Prisma |
81
- | `packages/auth/src/ui/` | React components: forms, auth-client, use-auth hook |
82
- | `packages/auth/src/ui/themed/` | CSS token files for themed UI (modern, minimal, colorful) |
83
- | `packages/auth/src/templates/` | Templates with variable substitution for stamped files |
84
- | `packages/auth/src/schema/` | Database schemas for Drizzle and Prisma |
85
- | `packages/cli/src/` | CLI commands, detector, thinker, writer, showbaby, config |
86
- | `registry/auth/latest.json` | Module manifest that describes what gets stamped |
87
-
88
- ---
89
-
90
- ## How Stamping Works
91
-
92
- When a user runs `sedim add auth`, the CLI reads from `packages/auth/src/` and stamps the selected files into the user's project. The user owns those files forever - they are not a runtime dependency.
93
-
94
- This means one rule you should never break: **do not add imports from `@sedim/auth` into stamped files**. Stamped files run in the user's project, which may not have `@sedim/auth` installed.
95
-
96
- ---
97
-
98
- ## How the CLI Works
99
-
100
- When you run `sedim add auth`, the CLI moves through four stages:
101
-
102
- ```
103
- detector → thinker → writer
104
- ```
105
-
106
- **1. Detector** (`packages/cli/src/detector/`)
107
- Reads the user's project files and produces a `DetectedContext`: framework, ORM, database, language, module system, and project structure. This is what drives every decision downstream.
108
-
109
- **2. Thinker** (`packages/cli/src/thinker/`)
110
- `load-plan-config.ts` tries to load the module's own `plan-config.ts` via dynamic import. If it exists, it calls `createAuthPlanConfig(ctx, selectedFeatures)` to get a rich, framework-aware plan. If not, it falls back to a generic manifest-based planner.
111
-
112
- `build-plan.ts` takes the plan config and selected features and produces an `InstallPlan`: what files to create, what to inject where, what dependencies to install, what env vars to add.
113
-
114
- **3. Writer** (`packages/cli/src/writer/`)
115
- `apply-plan.ts` executes the approved plan. It writes files (`write-file.ts`), injects imports and code snippets (`inject-imports.ts`, `inject-code.ts`), and updates `.env` (`update-env.ts`).
116
-
117
- The session (`packages/cli/src/session/`) saves progress after each stage. If the process is interrupted, `sedim continue auth` picks up from where it left off.
118
-
119
- **The plan-config is the module interface**
120
- Each module's `plan-config.ts` is the contract between the module and the CLI. It exports a function that takes `DetectedContext` and `selectedFeatures[]` and returns a `PlanConfig` that describes exactly what to stamp. The CLI never needs to know anything specific about a module - it just reads the plan config and executes it.
121
-
122
- ---
123
-
124
- ## Ways to Contribute
125
-
126
- ### Fix a bug
127
-
128
- If you found a bug, open an issue with the label `bug`. If you want to fix it yourself:
129
-
130
- 1. Check the issue to make sure it is confirmed
131
- 2. Fork the repo and create a branch from `main`
132
- 3. Fix it
133
- 4. Run `pnpm biome check .` to check formatting
134
- 5. Open a PR against `main`
135
-
136
- ### Add a framework adapter
137
-
138
- The auth module currently supports Next.js, Express, and Hono. Adding a new framework adapter (e.g., Fastify, SvelteKit) is a great way to expand Sedim's reach.
139
-
140
- Steps:
141
-
142
- 1. Create `packages/auth/src/adapters/framework/<framework>.ts` - look at `express.ts` or `hono.ts` as your reference
143
- 2. Implement the `DatabaseAdapter` interface and wire in all auth operations from `operations.ts`
144
- 3. Add the new framework to the detector in `packages/cli/src/detector/detect-framework.ts`
145
- 4. Add route and middleware templates in `packages/auth/src/templates/`
146
- 5. Test it with a new playground fixture or extend an existing one
147
- 6. Update the manifest in `registry/auth/latest.json`
148
-
149
- ### Add an ORM adapter
150
-
151
- Drizzle and Prisma are currently supported. To add a new ORM (e.g., Prisma but for a different database, or a different ORM library):
152
-
153
- 1. Create `packages/auth/src/adapters/<orm>.ts`
154
- 2. Implement the `DatabaseAdapter` interface - look at `drizzle.ts` and `prisma.ts` for the shape
155
- 3. Add the new ORM detection in `packages/cli/src/detector/detect-orm.ts`
156
- 4. Add the schema template for the new ORM in `packages/auth/src/schema/`
157
- 5. Test it with the playground fixtures
158
- 6. Update the manifest
159
-
160
- ### Add a new module
161
-
162
- Sedim is designed to support any feature module, not just auth. A module lives in `packages/<module-name>/` with its own `plan-config.ts` that tells the CLI what to stamp.
163
-
164
- Steps:
165
-
166
- 1. Create `packages/<module-name>/src/` with your module source
167
- 2. Create `packages/<module-name>/src/plan-config.ts` exporting `create<ModuleName>PlanConfig`
168
- 3. Create `registry/<module-name>/latest.json` with the module manifest
169
- 4. The CLI will automatically pick it up via `load-plan-config.ts`
170
-
171
- See the auth module's `plan-config.ts` as a reference - it maps feature selections to template keys and output paths.
172
-
173
- ### Add more features to the auth module
174
-
175
- You can add to the auth module without building a whole new adapter:
176
-
177
- - **New auth provider** (e.g., Apple OAuth, Microsoft OAuth) - add the provider to `framework-config.ts`, add PKCE flow to `operations.ts`, add UI button
178
- - **New email transport** (e.g., Mailgun, AWS SES beyond the current setup) - extend `email-transport.ts`
179
- - **New UI component** - add to `packages/auth/src/ui/` and wire it into `plan-config.ts`
180
- - **New theme variant** - create a new CSS token file in `packages/auth/src/ui/themed/`
181
- - **New database feature** - add to the schema files in `packages/auth/src/schema/`
182
-
183
- Steps:
184
-
185
- 1. Add the feature code in the appropriate directory
186
- 2. Update `plan-config.ts` to include the new files when the feature is selected
187
- 3. Update `registry/auth/latest.json` if adding new features that change what gets stamped
188
- 4. Add tests
189
- 5. Test with `sedim add auth` in a playground fixture
190
-
191
- ### Improve the CLI
192
-
193
- The CLI is in `packages/cli/src/`. You can work on:
194
-
195
- - New commands (`src/commands/`)
196
- - New detector strategies for frameworks, ORMs, or databases (`src/detector/`)
197
- - Improving the thinker / planning engine (`src/thinker/`)
198
- - Improving the writer / file operations (`src/writer/`)
199
- - Improving the UX, prompts, spinners, and summaries (`src/showbaby/`)
200
-
201
- ### Improve documentation
202
-
203
- The docs live in `apps/docs/`. If you find a broken link, an unclear explanation, or a missing guide, fix it. The docs are just Markdown files - you can edit them directly.
204
-
205
- ### Improve UI / accessibility
206
-
207
- The auth module's UI components are in `packages/auth/src/ui/`. If you want to improve them:
208
-
209
- - Accessibility: ARIA labels, keyboard navigation, focus management, screen reader support
210
- - UX: better error states, loading states, form validation messages
211
- - Design: visual refinements to the themed components, new theme variants
212
-
213
- ### Suggest a feature
214
-
215
- Open an issue with the label `enhancement` or `feature-request`. Describe what you want to build, why it would be useful, and if possible, how you would approach it. For big features, it's good to discuss before implementing.
216
-
217
- ---
218
-
219
- ## Playground Fixtures
220
-
221
- Fixtures are real apps in `apps/playground/` that the CLI is tested against. Each fixture is a minimal project with a specific stack.
222
-
223
- Current fixtures:
224
-
225
- | Fixture | Stack |
226
- |---------|-------|
227
- | `nextjs-drizzle-ts` | Next.js + Drizzle + TypeScript |
228
- | `express-prisma-ts` | Express + Prisma + TypeScript |
229
- | `hono-no-orm-js` | Hono + plain JS, no ORM |
230
- | `nextjs-existing-auth` | Next.js with existing next-auth (tests conflict detection) |
231
-
232
- To add a new fixture:
233
-
234
- 1. Create the project structure in `apps/playground/<fixture-name>/`
235
- 2. Add a minimal `sedim.config.ts` and the minimum files needed for the framework
236
- 3. Run through the full `sedim add auth` flow to verify it works
237
- 4. Test with `sedim diff auth` and `sedim add auth --dry-run` before running for real
238
-
239
- To run a fixture test:
240
-
241
- ```bash
242
- # Initialize
243
- pnpm --filter @sedim/cli exec tsx src/index.ts init --force --cwd apps/playground/nextjs-drizzle-ts
244
-
245
- # Preview what would be stamped
246
- pnpm --filter @sedim/cli exec tsx src/index.ts diff auth --cwd apps/playground/nextjs-drizzle-ts
247
-
248
- # Actually stamp
249
- pnpm --filter @sedim/cli exec tsx src/index.ts add auth --cwd apps/playground/nextjs-drizzle-ts
250
- ```
251
-
252
- To reset a fixture:
253
-
254
- ```bash
255
- rm apps/playground/<fixture-name>/sedim.config.ts
256
- rm -rf apps/playground/<fixture-name>/src/sedim/
257
- ```
258
-
259
- Do not push any code changes that you do in the playground except setting up a new fixture. It's only for proof of work and testing integration locally instead of having to do npm link each time changes are made.
260
-
261
- ---
262
-
263
- ## Testing
264
-
265
- ### Auth module tests
266
-
267
- Tests are in `packages/auth/src/__tests__/`. Run them with:
268
-
269
- ```bash
270
- cd packages/auth
271
- pnpm test
272
- ```
273
-
274
- To add a new test:
275
-
276
- 1. Create `packages/auth/src/__tests__/your-feature.test.ts`
277
- 2. Use `mock-db.ts` for the `DatabaseAdapter`
278
- 3. Import from the actual source files, not from stamped paths
279
-
280
- ### CLI tests
281
-
282
- CLI tests are in `packages/cli/src/__tests__/` or similar. Run them with:
283
-
284
- ```bash
285
- cd packages/cli
286
- pnpm test
287
- ```
288
-
289
- ### TypeScript must pass
290
-
291
- Before submitting any PR:
292
-
293
- ```bash
294
- cd packages/auth
295
- npx tsc --noEmit --skipLibCheck
296
- ```
297
-
298
- All non-template source must compile without errors. Only files with `{{PLACEHOLDERS}}` (template files) are allowed to have deliberate TS errors.
299
-
300
- ---
301
-
302
- ## Code Style
303
-
304
- - **TypeScript** - strict mode, no `any`, narrow properly
305
- - **Vitest** for all tests
306
- - **Biome** for linting and formatting
307
-
308
- Run Biome before committing:
309
-
310
- ```bash
311
- pnpm biome check .
312
- pnpm biome format --write .
313
- ```
314
-
315
- Biome runs in CI. PRs that fail Biome checks will be blocked.
316
-
317
- ---
318
-
319
- ## Commit Messages
320
-
321
- Use the `[type](scope)` format:
322
-
323
- ```
324
- [CLI](commands) : add interactive confirm prompt before stamping
325
- [AUTH](core) : add Apple OAuth provider support
326
- [CLI](detector) : add SvelteKit framework detection
327
- [AUTH](ui) : fix keyboard navigation on LoginForm
328
- [DOCS] : add guide for setting up OAuth providers
329
- [PLAYGROUND] : add Fastify fixture
330
- ```
331
-
332
- Valid scope options:
333
-
334
- | Scope | Where |
335
- |-------|-------|
336
- | `core` | packages/auth/src/core/ |
337
- | `adapters` | packages/auth/src/adapters/ |
338
- | `ui` | packages/auth/src/ui/ |
339
- | `templates` | packages/auth/src/templates/ |
340
- | `schema` | packages/auth/src/schema/ |
341
- | `plan-config` | packages/auth/src/plan-config.ts |
342
- | `thinker` | packages/cli/src/thinker/ |
343
- | `writer` | packages/cli/src/writer/ |
344
- | `detector` | packages/cli/src/detector/ |
345
- | `showbaby` | packages/cli/src/showbaby/ |
346
- | `commands` | packages/cli/src/commands/ |
347
- | `docs` | apps/docs/ |
348
- | `registry` | registry/ |
349
-
350
- ---
351
-
352
- ## Opening an Issue
353
-
354
- If you find a bug or want to suggest a feature:
355
-
356
- 1. Search first to check if it already exists
357
- 2. For bugs: include what you expected, what happened, and steps to reproduce
358
- 3. For features: describe what you want to build and why it would help
359
-
360
- Use the issue templates if they are available. Good issues get faster responses.
361
-
362
- ---
363
-
364
- ## Opening a Pull Request
365
-
366
- 1. Fork the repo and create a branch from `main`
367
- 2. Run `pnpm biome check .` and fix any issues
368
- 3. Make your changes
369
- 4. Test them - run the relevant fixture or tests
370
- 5. Push and open a PR against `main`
371
- 6. Describe what changed and why in the PR body
372
-
373
- For big changes (a new framework adapter, a new module, a significant feature), open an issue first to discuss before doing the work. This saves you from building something that might need a different approach.
374
-
375
- PRs are reviewed within a few days.
376
-
377
- ---
378
-
379
- ## Questions?
380
-
381
- Open an issue at https://github.com/Sedimie/Sedim or drop a message on Discord.
382
-
383
- ---
384
-
385
- *Last updated: 2026-05-24*
package/README.md DELETED
@@ -1,298 +0,0 @@
1
- # Sedim
2
- ![Sedim Banner](/assets/banner.jpeg)
3
-
4
- [![Discord](https://img.shields.io/discord/1340085528308782080?color=7289DA&logo=discord&logoColor=white&label=discord)](https://discord.com/invite/H7yutstM)
5
- [![GitHub Stars](https://img.shields.io/github/stars/Sedimie/Sedim?style=flat&logo=github)](https://github.com/Sedimie/Sedim)
6
- [![npm downloads](https://img.shields.io/npm/dw/@sedim/cli?label=weekly%20downloads)](https://www.npmjs.com/package/@sedim/cli)
7
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
8
-
9
- **Install complete features. Own every line.**
10
-
11
- Sedim is an open-source codegen CLI that stamps full-stack modules into your project, with out of the box working defaults. No runtime dependencies, no black boxes - every stamped file is readable, editable, and owned by you. Skip the 80% work done repetetively for just the 20% customizations on top.
12
-
13
- ```bash
14
- npm install -g @sedim/cli
15
-
16
- sedim init # detects your stack
17
- sedim add auth # stamps auth into your project
18
- ```
19
-
20
- The first POC for the stamping model is the Auth Module. Currently supports NextJS ( full stack ) ,Hono and Express (with react and vue frontends).
21
-
22
- ---
23
-
24
- ## See It In Action
25
-
26
- <!-- Replace with your actual YouTube embed or linked thumbnail -->
27
- [![Sedim Full Walkthrough](https://img.youtube.com/vi/YOUR_VIDEO_ID/maxresdefault.jpg)](https://www.youtube.com/watch?v=YOUR_VIDEO_ID)
28
-
29
- > 10-minute walkthrough - init, auth install, OAuth, TOTP, UI themes, and customization.
30
-
31
- ---
32
-
33
- ## Quick Start
34
-
35
- **Requirements:** Node ≥ 18, an existing project with a supported framework and ORM.
36
-
37
- ### 1. Install the CLI
38
-
39
- ```bash
40
- npm install -g @sedim/cli
41
- ```
42
-
43
- ### 2. Initialise your project
44
-
45
- ```bash
46
- cd my-project
47
- sedim init
48
- ```
49
-
50
- Sedim detects your framework, ORM, and language and writes a `sedim.config.ts`. If anything is detected incorrectly, edit the config file directly.
51
-
52
- ### 3. Add auth
53
-
54
- ```bash
55
- sedim add auth
56
- ```
57
- `Before writing the module directly, you can either run plan, diff or dry-run commands for the module as well!`
58
-
59
- The CLI walks you through:
60
-
61
- - **Environment detection** : confirms your framework, ORM, and language
62
- - **Feature selection** : email/password, OAuth providers, TOTP, magic links, JWT, RBAC/ABAC
63
- - **Frontend style** : headless, Tailwind styled, or themed with CSS tokens
64
- - **Confirm the plan** : review exactly what files will be stamped before anything is written
65
- - **Stamp** : files land in `src/sedim/auth/`
66
- - **Environment variables** : add them on the spot or copy the printed list to your `.env`
67
- ### 4. Migrate and run
68
-
69
- ```bash
70
- # Drizzle
71
- npx drizzle-kit push
72
-
73
- # or Prisma
74
- npx prisma migrate dev --name add_auth
75
-
76
- npm run dev
77
- ```
78
-
79
- ---
80
-
81
- ## What Gets Stamped
82
-
83
- Running `sedim add auth` generates this structure in your project. You own every file.
84
-
85
- The exact files that get stamped depend on the features you select during `sedim add auth` - OAuth providers, TOTP, magic links, JWT, and UI tier all gate which files are written. The structure below shows the full set of possible files; your install will include only the ones your selections require.
86
-
87
- ```
88
- src/sedim/auth/
89
- ├── core/
90
- │ ├── hash-password.ts — Argon2id password hashing
91
- │ ├── generate-token.ts — session tokens, OTP codes, backup codes, PKCE verifiers
92
- │ ├── session.ts — session building and sliding-window validation
93
- │ ├── pkce.ts — RFC 7636 PKCE (S256 only)
94
- │ ├── totp.ts — RFC 6238 TOTP (Google Authenticator compatible)
95
- │ ├── totp-crypto.ts — AES-256-GCM encryption for TOTP secrets
96
- │ ├── rate-limit.ts — sliding-window rate limiter
97
- │ ├── rbac.ts — role-based access control
98
- │ ├── abac.ts — attribute-based access control
99
- │ ├── jwt.ts — hybrid JWT (short-lived signed + DB-backed refresh)
100
- │ ├── oidc.ts — OIDC discovery and id_token validation
101
- │ └── email-transport.ts — multi-transport email (nodemailer/resend/postmark/ses)
102
- ├── adapters/
103
- │ ├── framework/
104
- │ │ ├── nextjs.ts — Next.js App Router handler factory
105
- │ │ ├── express.ts — Express router
106
- │ │ ├── hono.ts — Hono route registration
107
- │ │ ├── operations.ts — all auth operations (login, signup, OAuth, TOTP, etc.)
108
- │ │ └── framework-config.ts — OAuth provider configuration
109
- │ ├── drizzle.ts — Drizzle ORM adapter
110
- │ ├── prisma.ts — Prisma ORM adapter
111
- │ └── types.ts — DatabaseAdapter interface and types
112
- ├── ui/
113
- │ ├── auth-client.ts — client-side auth fetch utilities
114
- │ ├── use-auth.ts — React hook for auth state
115
- │ ├── headless/ — unstyled, logic-only components
116
- │ │ ├── LoginForm.tsx
117
- │ │ ├── SignupForm.tsx
118
- │ │ ├── ForgotPasswordForm.tsx
119
- │ │ ├── ResetPasswordForm.tsx
120
- │ │ ├── MagicLinkForm.tsx
121
- │ │ ├── OAuthButton.tsx
122
- │ │ └── TotpVerifyForm.tsx
123
- │ ├── tailwind/ — Tailwind-styled components
124
- │ └── themed/ — pre-built themes with CSS tokens
125
- │ ├── modern-tokens.css — glassmorphism theme
126
- │ ├── minimal-tokens.css — neumorphism theme
127
- │ └── colorful-tokens.css — neubrutalism theme
128
- ├── emails/
129
- │ └── email-verification.ts — email template for verification
130
- ├── schema.ts — Drizzle schema (users, sessions, oauth_accounts, etc.)
131
- └── index.ts — module barrel export
132
- ```
133
-
134
- The stamped auth route handler lands at `src/app/api/auth/[...all]/route.ts` (Next.js) or equivalent for other frameworks.
135
-
136
- ---
137
-
138
- ## Auth Module
139
-
140
- Auth is the first Sedim module. It ships with everything, none of it is a black box.
141
-
142
- [Screencast from 2026-05-24 17-31-01.webm](https://github.com/user-attachments/assets/7f444748-d0bf-4329-a4cc-60507ae8b4df)
143
-
144
-
145
- ### Features
146
-
147
- | Feature | Detail |
148
- |---|---|
149
- | **Password auth** | Argon2id (OWASP params), account lockout after 10 failed attempts |
150
- | **Session management** | SHA-256 hashed tokens, httpOnly cookies, full revocation |
151
- | **OAuth** | Google, GitHub, Discord : PKCE (RFC 7636) on all flows |
152
- | **TOTP** | RFC 6238, AES-256-GCM encrypted secrets at rest, backup codes |
153
- | **Magic links** | No email enumeration, supports SMTP / Resend / Postmark / SES |
154
- | **JWT** | Hybrid: short-lived signed JWTs + DB-backed refresh tokens |
155
- | **RBAC / ABAC** | Role and attribute-based access control middleware |
156
- | **Rate limiting** | Sliding window, in-memory or Redis store |
157
-
158
- ### Stack Support
159
-
160
- | Framework | Drizzle | Prisma |
161
- |-----------|:-------:|:------:|
162
- | Next.js (App Router) | ✓ | ✓ |
163
- | Express | ✓ | ✓ |
164
- | Hono | ✓ | ✓ |
165
-
166
- | Email provider | Supported |
167
- |---|:---:|
168
- | Nodemailer (SMTP) | ✓ |
169
- | Resend | ✓ |
170
- | Postmark | ✓ |
171
- | AWS SES | ✓ |
172
-
173
- ### UI Tiers
174
-
175
- Three levels so you use your own design system or ship immediately.
176
-
177
- [Screencast from 2026-05-24 17-36-47.webm](https://github.com/user-attachments/assets/2c910cd5-8de8-4468-a2fd-db5011edd8d2)
178
-
179
-
180
- **Headless** - zero CSS, pure logic and markup. Bring your own styles.
181
-
182
- **Tailwind** - fully styled with Tailwind classes, works with your existing Tailwind config.
183
-
184
- **Themed** - pre-built themes with CSS tokens. Currently ships `minimal` and `glass`.
185
-
186
- ### Environment Variables
187
-
188
- ```bash
189
- # Required
190
- AUTH_SECRET= # min 32 chars, used for session signing
191
- DATABASE_URL= # your database connection string
192
-
193
- # OAuth - add only the providers you selected
194
- GOOGLE_CLIENT_ID=
195
- GOOGLE_CLIENT_SECRET=
196
- GITHUB_CLIENT_ID=
197
- GITHUB_CLIENT_SECRET=
198
- DISCORD_CLIENT_ID=
199
- DISCORD_CLIENT_SECRET=
200
-
201
- # Email - add only the provider you selected
202
- SMTP_HOST=
203
- SMTP_PORT=
204
- SMTP_USER=
205
- SMTP_PASS=
206
- RESEND_API_KEY=
207
- POSTMARK_API_KEY=
208
- AWS_ACCESS_KEY_ID=
209
- AWS_SECRET_ACCESS_KEY=
210
- AWS_SES_REGION=
211
-
212
- # Optional
213
- REDIS_URL= # if using Redis for rate limiting or sessions
214
- TOTP_ENCRYPTION_KEY= # required if TOTP is enabled, 32-byte hex
215
- ```
216
-
217
- ---
218
-
219
- ## Architecture
220
-
221
- Sedim uses a **stamp model**, not a runtime SDK:
222
-
223
- ```
224
- sedim add auth → generates files into src/sedim/auth/
225
- (standalone forever, no sedim dependency at runtime)
226
- ```
227
-
228
- The CLI has four components:
229
-
230
- | Component | What it does |
231
- |---|---|
232
- | **Detector** | Reads your project, framework, ORM, language, existing config |
233
- | **Planner (Thinker)** | Combines the module manifest with your feature selections into a stamp plan |
234
- | **Writer** | Executes the plan, generates files, migrations, env var list |
235
- | **Showbaby** | Shows you exactly what was stamped and what to do next |
236
-
237
- Every module is described by a **manifest** (`registry/<module>/latest.json`) - a declarative spec of every file the module can stamp, what features gate each file, and what environment variables are required. The CLI reads the manifest, applies your choices, and stamps only what you need.
238
-
239
- ```mermaid
240
- flowchart LR
241
- Dev["Developer\nruns: sedim add auth"] --> Detector
242
- Detector --> Thinker
243
- RegistryJSON["Registry\nregistry/auth/latest.json"] --> Thinker
244
- Thinker --> Writer
245
- Writer --> StampedFiles["src/sedim/auth/\nuser-owned stamped files"]
246
-
247
- RegistryJSON --> Dev
248
-
249
- Thinker --> Plan["InstallPlan\napproved by user"]
250
- Plan --> Writer
251
-
252
- style Dev fill:#1a1a1a,color:#ffffff
253
- style StampedFiles fill:#1a1a1a,color:#ffffff
254
- style RegistryJSON fill:#333,color:#fff
255
- style Plan fill:#333,color:#fff
256
- ```
257
-
258
- The module source lives in `packages/<module>/src/` - this is where auth logic, UI components, adapters, and templates live. The CLI reads from here when stamping. `packages/core/` holds shared TypeScript types used by both the CLI and all modules.
259
-
260
- ---
261
-
262
- ## Registry
263
-
264
- Module manifests live in the [`registry/`](https://github.com/Sedimie/Sedim/tree/main/registry) directory. The CLI uses the local registry during development and falls back to the GitHub raw URL for published releases.
265
-
266
- **Available modules:**
267
-
268
- | Module | Status |
269
- |---|---|
270
- | `auth` | Available |
271
- | `notifications` | On the roadmap |
272
- | `chat` | On the roadmap |
273
- | `WebRTC` | On the roadmap |
274
- | `WalletAdapters` | On the roadmap |
275
- | `ai-rag` | On the roadmap |
276
- | `payments` | On the roadmap |
277
-
278
- ---
279
- ## Philosophy
280
-
281
- Most tools give you an API to call. Customization is what's keeping modularizing full stack features at bay, but with codegen model, you own the code, and hence customize it however much you want. This is not just a library to cut your grunt work, you can learn the overall implementations it uses to be able to basically use the full stack features as boilerplate code.
282
-
283
- When you run `sedim add auth`, you get the auth system, not a dependency on one. The files live in your repo, show up in your git history, and bend to whatever you need them to do. Sedim writes the first version. Everything after that is yours.
284
-
285
- *The best code is code you own.*
286
-
287
-
288
- AI Agentic coding is another thing that this might clash with, but an AI tool might hallucinate and give 90% accuracy, leave out security considerations and make it tough to customize while also using up 3 hours and a considerable amount of tokens. This allows you to skip directly to the customizations part, with 100% hit-rate since it's static codegen, and 0 cost for the grunt work with upto date security standards being followed. Use AI tools on top of this to speed you up and make your workflow unbelievably fast.
289
-
290
- ---
291
-
292
- ### Check out the docs
293
- Full documentation - customization guides, adapter references, module authoring, and escape hatches - is at [sedim.dev/docs](https://sedim.dev/docs).
294
-
295
- ### Contributions
296
- To add a framework adapter, ORM adapter, or new module, see [CONTRIBUTING.md](./CONTRIBUTING.md).
297
-
298
- The module spec and adapter interface are documented there - adding a new adapter for a supported module takes a few hours once you understand the pattern.