{"id":26247962,"url":"https://github.com/stackpress/stackpress","last_synced_at":"2025-04-23T22:48:51.397Z","repository":{"id":281212497,"uuid":"938757434","full_name":"stackpress/stackpress","owner":"stackpress","description":"A Content Management Framework","archived":false,"fork":false,"pushed_at":"2025-04-23T07:31:16.000Z","size":1242,"stargazers_count":4,"open_issues_count":0,"forks_count":7,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-23T22:48:42.305Z","etag":null,"topics":["esm","nodejs","react","serverless","typescript"],"latest_commit_sha":null,"homepage":"https://www.stackpress.io","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stackpress.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-25T13:05:29.000Z","updated_at":"2025-04-23T07:31:20.000Z","dependencies_parsed_at":"2025-04-14T10:34:32.029Z","dependency_job_id":"836f426d-59bf-47be-8c19-5718d6bd5e65","html_url":"https://github.com/stackpress/stackpress","commit_stats":null,"previous_names":["stackpress/stackpress"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackpress%2Fstackpress","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackpress%2Fstackpress/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackpress%2Fstackpress/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackpress%2Fstackpress/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stackpress","download_url":"https://codeload.github.com/stackpress/stackpress/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250528693,"owners_count":21445511,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["esm","nodejs","react","serverless","typescript"],"created_at":"2025-03-13T14:16:24.373Z","updated_at":"2025-04-23T22:48:51.383Z","avatar_url":"https://github.com/stackpress.png","language":"TypeScript","readme":"# Stackpress\n\nStackpress is a content management framework. It combines several open \nsource projects maintained by the Stackpress Team.\n\n - [Idea](https://github.com/stackpress/idea)\n - [Ingest](https://github.com/stackpress/ingest)\n - [Inquire](https://github.com/stackpress/inquire)\n - [Reactus](https://github.com/stackpress/reactus)\n\n# Features \n\nThe goal of Stackpress is to build robust apps in days, not months.\n\n - Admin Generator\n - React Template Engine\n - Built-in SQL tools\n - Built-in User, Auth, Session, API, and Email plugins\n\n## Nuances\n\nUnlike other frameworks, we have chosen the following philosophies.\n\n - Server Side First\n - TS/ESM/CJS\n - Server/less framework\n - Unopinionated\n - Event Driven\n - Plugggable Design\n - Client Generator\n\n## Usage\n\n```js\nimport { server } from 'stackpress/http'\n\nconst app = server()\n\napp.get('/', (req, res) =\u003e {\n  const name = req.data.path('name', 'guest')\n  res.setBody('text/plain', `Hello ${name}`)\n})\n\napp.create().listen(3000, () =\u003e {\n  console.log('Server is running on port 3000')\n})\n```\n\nSee [Example](https://github.com/stackpress/stackpress/tree/main/example) \nfor use case.\n\n## Routing\n\nStackpress uses several routers for callbacks, lazy imports and React \ntemplates. You can access each router like the following.\n\n```js\n//action routing\napp.action.get('/home', (req, res, ctx) =\u003e {});\n//import routing\napp.import.get('/home', () =\u003e import('./pages/home'));\n//view routing (react)\napp.view.get('/home', '@/views/home');\n```\n\nLike other server frameworks, the following route methods are available.\n\n```js\n//common methods\napp.connect('/home', action)\napp.delete('/home', action)\napp.get('/home', action)\napp.head('/home', action)\napp.options('/home', action)\napp.patch('/home', action)\napp.post('/home', action)\napp.put('/home', action)\napp.trace('/home', action)\n//any method\napp.all('/home', action)\n//custom method\napp.route('get', '/home')\n```\n\nYou can let Stackpress infer your action implementation.\n\n```js\n//action callback\napp.get('/home', (req, res, ctx) =\u003e {});\n//lazy import action\napp.get('/home', () =\u003e import('./pages/home'));\n//react template\napp.get('/home', '@/views/home');\n```\n\nYou can prioritize routing in the following way where the highest number\ncalls first.\n\n```js\n//first\napp.get('/home', action, 100);\n//second\napp.get('/home', action);\n//third\napp.get('/home', action);\n//fourth\napp.get('/home', action, -100);\n```\n\n## Events\n\nRouting is built on top of events, a necessity to event driven design.\n\n```js\napp.on('email-send', logInDatabase)\napp.on('email-send', smtpQueue)\napp.on('email-send', updateDatabase)\n```\n\nLike routing, you can use action, imports and views.\n\n```js\n//action callback\napp.action.on('email-send', logInDatabase)\n//use a separate file\napp.import.on('email-send', () =\u003e import('/event/smtp-queue'))\n//set the response view\napp.view.on('email-send', '@/views/email/success')\n```\n\n## Database\n\nA minimal database setup would look like the following.\n\n```js\nimport path from 'node:path'\nimport { PGlite } from '@electric-sql/pglite'\nimport { connect } from 'stackpress/pglite'\n\nconst db = await connect(async () =\u003e {\n  return new PGlite(path.resolve(cwd, 'database'))\n})\n\napp.register('database', db);\n```\n\nStackpress has support for the following SQL packages.\n\n - `mysql2`\n - `pg`\n - `pglite`\n - `better-sqlite3`\n\nNo matter the SQL package, the query builder is exactly the same. See \nthe following example.\n\n```js\nconst products = await db.select('*').from('products').where('price \u003e %s', 100)\n```\n\nYou can do a raw query like this as well.\n\n```js\nconst users = await db.query('SELECT * from users')\n```\n\nAnd you can do transactions like this.\n\n```js\nawait db.transaction(async () =\u003e {\n  await db.update('users').set({ age: 100 }).where('age \u003e %s', 100)\n})\n```\n\n## Plugin\n\nThe following is an example of a basic plugin you can create in your \nproject or use from a Stackpress project in `node_modules`.\n\n```js\n//plugin.ts\nimport type { Server } from 'stackpress/server'\n\nexport default function MyPlugin(app: Server) {\n  //start plugging...\n  app.on('email-send', logInDatabase)\n  app.get('/signin', () =\u003e import('/page/signin'))\n}\n```\n\nWhile developing a plugin, you can get the project configuration like this.\n\n```js\nexport default function MyPlugin(app: Server) {\n  //get all the config\n  const config = app.config()\n  //traverse the config\n  const cwd = app.config\u003cstring\u003e('server', 'cwd')\n  //use dot pathing (default production)\n  const mode = app.config.path\u003cstring\u003e('server.mode', 'production')\n}\n```\n\nYou can register your plugin so other plugins can access like this.\n\n```js\nexport default function MyPlugin(app: Server) {\n  app.register('my-plugin', { foo: 'bar' })\n}\n```\n\nYou can add plugins by manually importing them xor using `package.json`.\n\n```js\n{\n  \"name\": \"my-project\",\n  \"plugins\": [ \"./plugin\", \"stackpress\" ],\n  \"dependencies\": {...}\n}\n```\n\nTo load (initialize) plugins you just need to run this code.\n\n```js\nawait app.bootstrap();\n```\n\nThen you can access plugins in your project like this.\n\n```js\nconst myPlugin = app.plugin('my-plugin')\n//or\nconst myPlugin2 = app.plugin\u003c{ foo: string }\u003e('my-plugin')\n```\n\n## Admin\n\nTo generate an admin you need to first create a `schema.idea` file in\nthe root of your project.\n\n```js\nmodel User @label(\"User\" \"Users\") @template(\"{{name}}\") @icon(\"user\") {\n  id   String @label(\"ID\") \n              @id @default(\"cuid()\")\n              @list.overflow({ length 10 hellip true })\n\n  name String @label(\"Name\") \n              @searchable\n              @field.text\n              @is.required\n              @list.text @view.text\n}\n```\n\nNext emit emit following events.\n\n```js\nawait app.emit('config')\nawait app.emit('listen')\nawait app.emit('route')\n```\n\nNext export a `const config` in your project root with the following configuration.\n\n```js\nexport const config = {\n  client: {\n    //used by `stackpress/client` to `import()` \n    //the generated client code to memory\n    module: '.client',\n    //where to store the generated client code\n    build: path.join(cwd, 'node_modules', '.client'),\n    //what tsconfig file to base the typescript compiler on\n    tsconfig: path.join(cwd, 'tsconfig.json')\n  }\n}\n```\n\nThen in terminal you can run the following.\n\n```bash\n$ npx stackpress index generate\n```\n\nThis will generate a `.client` folder in `node_modules`. You can check \nthe admin by visiting `http://localhost:3000/admin/user/search`. You can \nalso access the ORM like the following.\n\n```js\nimport type { ClientPlugin } from 'stackpress'\n\nconst client = app.plugin\u003cClientPlugin\u003e('client')\nconst user = await client.model.user.create({ name: 'John Doe' })\n```\n\nNew events will be available as well.\n\n```js\nimport type { User } from '.client'\n\nawait app.resolve\u003cUser\u003e('user-create', { name: 'John Doe' })\n```\n\n## Authentication\n\nTo use the default authentication, you need to add an `auth` configuration.\n\n```js\napp.config.set('auth', {\n  //base route for signin, signout, signup pages\n  base: '/auth',\n  //default roles for new users\n  roles: [ 'USER' ],\n  //allow signin with username\n  username: true,\n  //allow signin with email address\n  email: true,\n  //allow signin with phone number\n  phone: true\n})\n```\n\nNext you need to import the `stackpress.idea` file to your main \n`schema.idea`.\n\n```js\nuse \"stackpress/stackpress.idea\"\n//your models here...\n```\n\nLastly run the following in terminal.\n\n```bash\n$ npx stackpress transform\n$ npx stackpress push\n```\n\n## Permissions\n\nWhen you add a `session` configuration, your project will deny access to \nall pages *(blacklist by default)*. You can open/configure route access\nby roles using just the configuration.\n\n```js\napp.config.set('session', {\n  //name of the session cookie\n  key: 'session',\n  //used to generate the session id\n  //also used to encrypt/decrypt data \n  //in the database\n  seed: 'ABC123',\n  access: {\n    //role: permissions\n    GUEST: [\n      //dev routes\n      { method: 'ALL', route: '/@vite/client' },\n      { method: 'ALL', route: '/@react-refresh' },\n      { method: 'ALL', route: '/@fs/**' },\n      { method: 'ALL', route: '/node_modules/**' },\n      { method: 'ALL', route: '/__uno.css' },\n      { method: 'ALL', route: '/plugins/**' },\n      { method: 'ALL', route: '/react.svg' },\n      //public routes\n      { method: 'GET', route: '/assets/**' },\n      { method: 'GET', route: '/client/**' },\n      { method: 'GET', route: '/images/**' },\n      { method: 'GET', route: '/styles/**' },\n      { method: 'GET', route: '/favicon.ico' },\n      { method: 'GET', route: '/favicon.png' },\n      //page routes\n      { method: 'GET', route: '/' },\n      { method: 'ALL', route: '/auth/**' },\n      { method: 'ALL', route: '/admin/**' },\n      { method: 'ALL', route: '/api/**' }\n    ]\n  }\n})\n```\n\nBy default everyone is a `GUEST` and other role names are arbitrary.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackpress%2Fstackpress","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstackpress%2Fstackpress","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackpress%2Fstackpress/lists"}