-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move create-keystone-app package inside the monorepo (#9102)
Co-authored-by: Daniel Cousens <413395+dcousens@users.noreply.github.com>
- Loading branch information
1 parent
2849031
commit 0decc55
Showing
16 changed files
with
1,146 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2024 Thinkmill Labs Pty Ltd | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# create-keystone-app | ||
|
||
<br> | ||
<p>Keystone helps you build faster and scale further than any other CMS or App Framework. Describe your schema, and get a powerful GraphQL API & beautiful Management UI for your content and data.</p> | ||
<p>No boilerplate or bootstrapping – just elegant APIs to help you ship the code that matters without sacrificing the flexibility or power of a bespoke back-end. | ||
</p> | ||
|
||
For help with this package join the conversation in [Slack](https://community.keystonejs.com/), or on [GitHub](https://github.com/keystonejs/keystone/). | ||
|
||
Visit <https://keystonejs.com/> for docs, and [follow @keystonejs on Twitter](https://twitter.com/keystonejs) for the latest updates. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#!/usr/bin/env node | ||
import './dist/create-keystone-app.esm.js' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"name": "create-keystone-app", | ||
"version": "9.0.1", | ||
"license": "MIT", | ||
"type": "module", | ||
"main": "dist/create-keystone-app.cjs.js", | ||
"module": "dist/create-keystone-app.esm.js", | ||
"repository": "https://github.com/keystonejs/keystone/tree/main/packages/create", | ||
"bin": "./cli.js", | ||
"exports": { | ||
".": { | ||
"module": "./dist/create-keystone-app.esm.js", | ||
"default": "./dist/create-keystone-app.cjs.js" | ||
}, | ||
"./package.json": "./package.json" | ||
}, | ||
"preconstruct": { | ||
"entrypoints": [ | ||
"index.ts" | ||
] | ||
}, | ||
"dependencies": { | ||
"chalk": "^4.1.2", | ||
"enquirer": "^2.4.1", | ||
"execa": "^5.1.1", | ||
"meow": "^9.0.0", | ||
"ora": "^8.0.1", | ||
"package-json": "^10.0.0" | ||
}, | ||
"files": [ | ||
"dist", | ||
"starter", | ||
"cli.js" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import fs from 'node:fs/promises' | ||
import path from 'node:path' | ||
import { fileURLToPath } from 'node:url' | ||
|
||
import c from 'chalk' | ||
import enquirer from 'enquirer' | ||
import execa from 'execa' | ||
import getPackageJson from 'package-json' | ||
import meow from 'meow' | ||
import ora from 'ora' | ||
|
||
import thisPackage from '../package.json' | ||
|
||
async function checkVersion () { | ||
const { version: upstream } = await getPackageJson('create-keystone-app') | ||
if (upstream === thisPackage.version) return | ||
|
||
console.error(`⚠️ You're running an old version of create-keystone-app, please update to ${upstream}`) | ||
} | ||
|
||
class UserError extends Error {} | ||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url)) | ||
const starterDir = path.normalize(`${__dirname}/../starter`) | ||
|
||
const cli = meow(` | ||
Usage | ||
$ create-keystone-app [directory] | ||
`) | ||
|
||
async function normalizeArgs () { | ||
let directory = cli.input[0] | ||
if (!directory) { | ||
({ directory } = await enquirer.prompt({ | ||
type: 'input', | ||
name: 'directory', | ||
message: 'What directory should create-keystone-app generate your app into?', | ||
validate: (x) => !!x, | ||
})) | ||
process.stdout.write('\n') | ||
} | ||
|
||
return { | ||
directory: path.resolve(directory), | ||
} | ||
} | ||
|
||
(async () => { | ||
process.stdout.write('\n') | ||
console.log(`✨ You're about to generate a project using ${c.bold('Keystone 6')} packages.`) | ||
|
||
await checkVersion() | ||
const normalizedArgs = await normalizeArgs() | ||
const nextCwd = normalizedArgs.directory | ||
|
||
await fs.mkdir(nextCwd) | ||
await Promise.all([ | ||
'_gitignore', | ||
'schema.ts', | ||
'package.json', | ||
'tsconfig.json', | ||
'schema.graphql', | ||
'schema.prisma', | ||
'keystone.ts', | ||
'auth.ts', | ||
'README.md', | ||
].map((filename) => | ||
fs.copyFile( | ||
path.join(starterDir, filename), | ||
path.join(normalizedArgs.directory, filename.replace(/^_/, '.')) | ||
) | ||
)) | ||
|
||
const [packageManager] = process.env.npm_config_user_agent?.split('/', 1) ?? ['npm'] | ||
const spinner = ora(`Installing dependencies with ${packageManager}. This may take a few minutes.`).start() | ||
try { | ||
await execa(packageManager, ['install'], { cwd: nextCwd }) | ||
spinner.succeed(`Installed dependencies with ${packageManager}.`) | ||
} catch (err) { | ||
spinner.fail(`Failed to install with ${packageManager}.`) | ||
throw err | ||
} | ||
|
||
const relativeProjectDir = path.relative(process.cwd(), normalizedArgs.directory) | ||
process.stdout.write('\n') | ||
console.log(`🎉 Keystone created a starter project in: ${c.bold(relativeProjectDir)} | ||
${c.bold('To launch your app, run:')} | ||
- cd ${relativeProjectDir} | ||
- ${packageManager} run dev | ||
${c.bold('Next steps:')} | ||
- Read ${c.bold( | ||
`${relativeProjectDir}${path.sep}README.md` | ||
)} for additional getting started details. | ||
- Edit ${c.bold( | ||
`${relativeProjectDir}${path.sep}keystone.ts` | ||
)} to customize your app. | ||
- Star Keystone on GitHub (https://github.com/keystonejs/keystone) | ||
)} | ||
`) | ||
})().catch((err) => { | ||
if (err instanceof UserError) { | ||
console.error(err.message) | ||
} else { | ||
console.error(err) | ||
} | ||
process.exit(1) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Keystone Project Starter | ||
|
||
Welcome to Keystone! | ||
|
||
Run | ||
|
||
``` | ||
yarn dev | ||
``` | ||
|
||
To view the config for your new app, look at [./keystone.ts](./keystone.ts) | ||
|
||
This project starter is designed to give you a sense of the power Keystone can offer you, and show off some of its main features. It's also a pretty simple setup if you want to build out from it. | ||
|
||
We recommend you use this alongside our [getting started walkthrough](https://keystonejs.com/docs/walkthroughs/getting-started-with-create-keystone-app) which will walk you through what you get as part of this starter. | ||
|
||
If you want an overview of all the features Keystone offers, check out our [features](https://keystonejs.com/why-keystone#features) page. | ||
|
||
## Some Quick Notes On Getting Started | ||
|
||
### Changing the database | ||
|
||
We've set you up with an [SQLite database](https://keystonejs.com/docs/apis/config#sqlite) for ease-of-use. If you're wanting to use PostgreSQL, you can! | ||
|
||
Just change the `db` property on line 16 of the Keystone file [./keystone.ts](./keystone.ts) to | ||
|
||
```typescript | ||
db: { | ||
provider: 'postgresql', | ||
url: process.env.DATABASE_URL || 'DATABASE_URL_TO_REPLACE', | ||
} | ||
``` | ||
|
||
And provide your database url from PostgreSQL. | ||
|
||
For more on database configuration, check out or [DB API Docs](https://keystonejs.com/docs/apis/config#db) | ||
|
||
### Auth | ||
|
||
We've put auth into its own file to make this humble starter easier to navigate. To explore it without auth turned on, comment out the `isAccessAllowed` on line 21 of the Keystone file [./keystone.ts](./keystone.ts). | ||
|
||
For more on auth, check out our [Authentication API Docs](https://keystonejs.com/docs/apis/auth#authentication-api) | ||
|
||
### Adding a frontend | ||
|
||
As a Headless CMS, Keystone can be used with any frontend that uses GraphQL. It provides a GraphQL endpoint you can write queries against at `/api/graphql` (by default [http://localhost:3000/api/graphql](http://localhost:3000/api/graphql)). At Thinkmill, we tend to use [Next.js](https://nextjs.org/) and [Apollo GraphQL](https://www.apollographql.com/docs/react/get-started/) as our frontend and way to write queries, but if you have your own favourite, feel free to use it. | ||
|
||
A walkthrough on how to do this is forthcoming, but in the meantime our [todo example](https://github.com/keystonejs/keystone-react-todo-demo) shows a Keystone set up with a frontend. For a more full example, you can also look at an example app we built for [Prisma Day 2021](https://github.com/keystonejs/prisma-day-2021-workshop) | ||
|
||
### Embedding Keystone in a Next.js frontend | ||
|
||
While Keystone works as a standalone app, you can embed your Keystone app into a [Next.js](https://nextjs.org/) app. This is quite a different setup to the starter, and we recommend checking out our walkthrough for that [here](https://keystonejs.com/docs/walkthroughs/embedded-mode-with-sqlite-nextjs#how-to-embed-keystone-sq-lite-in-a-next-js-app). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
.keystone/ | ||
keystone.db | ||
*.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Welcome to some authentication for Keystone | ||
// | ||
// This is using @keystone-6/auth to add the following | ||
// - A sign-in page for your Admin UI | ||
// - A cookie-based stateless session strategy | ||
// - Using a User email as the identifier | ||
// - 30 day cookie expiration | ||
// | ||
// This file does not configure what Users can do, and the default for this starter | ||
// project is to allow anyone - logged-in or not - to do anything. | ||
// | ||
// If you want to prevent random people on the internet from accessing your data, | ||
// you can find out how by reading https://keystonejs.com/docs/guides/auth-and-access-control | ||
// | ||
// If you want to learn more about how our out-of-the-box authentication works, please | ||
// read https://keystonejs.com/docs/apis/auth#authentication-api | ||
|
||
import { randomBytes } from 'node:crypto' | ||
import { createAuth } from '@keystone-6/auth' | ||
|
||
// see https://keystonejs.com/docs/apis/session for the session docs | ||
import { statelessSessions } from '@keystone-6/core/session' | ||
|
||
// for a stateless session, a SESSION_SECRET should always be provided | ||
// especially in production (statelessSessions will throw if SESSION_SECRET is undefined) | ||
let sessionSecret = process.env.SESSION_SECRET | ||
if (!sessionSecret && process.env.NODE_ENV !== 'production') { | ||
sessionSecret = randomBytes(32).toString('hex') | ||
} | ||
|
||
// withAuth is a function we can use to wrap our base configuration | ||
const { withAuth } = createAuth({ | ||
listKey: 'User', | ||
identityField: 'email', | ||
|
||
// this is a GraphQL query fragment for fetching what data will be attached to a context.session | ||
// this can be helpful for when you are writing your access control functions | ||
// you can find out more at https://keystonejs.com/docs/guides/auth-and-access-control | ||
sessionData: 'name createdAt', | ||
secretField: 'password', | ||
|
||
// WARNING: remove initFirstItem functionality in production | ||
// see https://keystonejs.com/docs/config/auth#init-first-item for more | ||
initFirstItem: { | ||
// if there are no items in the database, by configuring this field | ||
// you are asking the Keystone AdminUI to create a new user | ||
// providing inputs for these fields | ||
fields: ['name', 'email', 'password'], | ||
|
||
// it uses context.sudo() to do this, which bypasses any access control you might have | ||
// you shouldn't use this in production | ||
}, | ||
}) | ||
|
||
// statelessSessions uses cookies for session tracking | ||
// these cookies have an expiry, in seconds | ||
// we use an expiry of 30 days for this starter | ||
const sessionMaxAge = 60 * 60 * 24 * 30 | ||
|
||
// you can find out more at https://keystonejs.com/docs/apis/session#session-api | ||
const session = statelessSessions({ | ||
maxAge: sessionMaxAge, | ||
secret: sessionSecret!, | ||
}) | ||
|
||
export { withAuth, session } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Welcome to Keystone! | ||
// | ||
// This file is what Keystone uses as the entry-point to your headless backend | ||
// | ||
// Keystone imports the default export of this file, expecting a Keystone configuration object | ||
// you can find out more at https://keystonejs.com/docs/apis/config | ||
|
||
import { config } from '@keystone-6/core' | ||
|
||
// to keep this file tidy, we define our schema in a different file | ||
import { lists } from './schema' | ||
|
||
// authentication is configured separately here too, but you might move this elsewhere | ||
// when you write your list-level access control functions, as they typically rely on session data | ||
import { withAuth, session } from './auth' | ||
|
||
export default withAuth( | ||
config({ | ||
db: { | ||
// we're using sqlite for the fastest startup experience | ||
// for more information on what database might be appropriate for you | ||
// see https://keystonejs.com/docs/guides/choosing-a-database#title | ||
provider: 'sqlite', | ||
url: 'file:./keystone.db', | ||
}, | ||
lists, | ||
session, | ||
}) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "keystone-app", | ||
"version": "1.0.3", | ||
"private": true, | ||
"scripts": { | ||
"dev": "keystone dev", | ||
"start": "keystone start", | ||
"build": "keystone build", | ||
"postinstall": "keystone build --no-ui --frozen" | ||
}, | ||
"dependencies": { | ||
"@keystone-6/auth": "^8.0.0", | ||
"@keystone-6/core": "^6.0.0", | ||
"@keystone-6/fields-document": "^9.0.0", | ||
"typescript": "^5.5.0" | ||
} | ||
} |
Oops, something went wrong.