-
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.
refactor: move create-keystone-app inside monorepo
- Loading branch information
1 parent
3b6ba78
commit c5f6d71
Showing
18 changed files
with
1,819 additions
and
231 deletions.
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) 2021 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,6 @@ | ||
# @keystone-6/create | ||
|
||
Keystone-6 is the latest version of Keystone. | ||
To get help with this package join the conversation in [Slack](https://community.keystonejs.com/), or [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,43 @@ | ||
{ | ||
"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", | ||
"fs-extra": "^11.0.0", | ||
"meow": "^9.0.0", | ||
"ora": "^8.0.1", | ||
"package-json": "^10.0.0", | ||
"path": "^0.12.7", | ||
"semver": "^7.6.0", | ||
"terminal-link": "^3.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/fs-extra": "^11.0.0", | ||
"@types/semver": "^7.5.8" | ||
}, | ||
"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,24 @@ | ||
import getPackageJson from 'package-json'; | ||
import currentPkgJson from '../package.json'; | ||
import * as semver from 'semver'; | ||
|
||
export async function checkVersion() { | ||
try { | ||
const { version } = await getPackageJson('create-keystone-app'); | ||
if (typeof version !== 'string') { | ||
throw new Error( | ||
'version from package metadata was expected to be a string but was not' | ||
); | ||
} | ||
if (semver.lt(currentPkgJson.version, version)) { | ||
console.error( | ||
`⚠️ You're running an old version of create-keystone-app, please update to ${version}` | ||
); | ||
} | ||
} catch (err) { | ||
console.error( | ||
'A problem occurred fetching the latest version of create-keystone-app' | ||
); | ||
console.error(err); | ||
} | ||
} |
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,135 @@ | ||
import fs from 'fs-extra'; | ||
import path from 'path'; | ||
import meow from 'meow'; | ||
import enquirer from 'enquirer'; | ||
import execa from 'execa'; | ||
import ora from 'ora'; | ||
import c from 'chalk'; | ||
import terminalLink from 'terminal-link'; | ||
import { checkVersion } from './checkVersion'; | ||
import { UserError } from './utils'; | ||
import { fileURLToPath } from 'url'; | ||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||
const starterDir = path.normalize(`${__dirname}/../starter`); | ||
|
||
const cli = meow( | ||
` | ||
Usage | ||
$ create-keystone-app [directory] | ||
` | ||
); | ||
|
||
type Args = { | ||
directory: string; | ||
}; | ||
|
||
const versionInfo = () => { | ||
process.stdout.write('\n'); | ||
console.log(`✨ You're about to generate a project using ${c.bold( | ||
'Keystone 6' | ||
)} packages. | ||
`); | ||
}; | ||
|
||
async function normalizeArgs(): Promise<Args> { | ||
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), | ||
}; | ||
} | ||
|
||
function pkgManagerFromUserAgent(userAgent: string | undefined) { | ||
if (!userAgent) return 'npm'; | ||
const pkgSpec = userAgent.split(' ')[0]; | ||
const [name, _version] = pkgSpec.split('/'); | ||
return name ?? 'npm'; | ||
} | ||
|
||
const installDeps = async (cwd: string): Promise<string> => { | ||
const pkgManager = pkgManagerFromUserAgent(process.env.npm_config_user_agent); | ||
const spinner = ora( | ||
`Installing dependencies with ${pkgManager}. This may take a few minutes.` | ||
).start(); | ||
try { | ||
await execa(pkgManager, ['install'], { cwd }); | ||
spinner.succeed(`Installed dependencies with ${pkgManager}.`); | ||
return pkgManager; | ||
} catch (err) { | ||
spinner.fail(`Failed to install with ${pkgManager}.`); | ||
throw err; | ||
} | ||
}; | ||
|
||
(async () => { | ||
versionInfo(); | ||
await checkVersion(); | ||
const normalizedArgs = await normalizeArgs(); | ||
await fs.mkdir(normalizedArgs.directory); | ||
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 = await installDeps(normalizedArgs.directory); | ||
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. | ||
- ${terminalLink('Open the Admin UI', 'http://localhost:3000')} | ||
- ${terminalLink('Open the Graphql API', 'http://localhost:3000/api/graphql')} | ||
- ${terminalLink('Read the docs', 'https://keystonejs.com')} | ||
- ${terminalLink( | ||
'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 @@ | ||
export class UserError extends Error {} |
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 @@ | ||
# keystone-app | ||
|
||
## 1.0.2 | ||
|
||
### Patch Changes | ||
|
||
- [`3b4360a`](https://github.com/keystonejs/create-keystone-app/commit/3b4360a114f00094e40fdc89dd4c82e1456b9ae5) Thanks [@dcousens](https://github.com/dcousens)! - Fix graphql@^15.8.0 and next@12.2.4 as pseudo-peer dependencies until next `@keystone-6/core` release | ||
|
||
## 1.0.1 | ||
|
||
### Patch Changes | ||
|
||
- [#278](https://github.com/keystonejs/create-keystone-app/pull/278) [`26f9a79`](https://github.com/keystonejs/create-keystone-app/commit/26f9a79ef913915bac85657884f85ff7e4da46c2) Thanks [@Noviny](https://github.com/Noviny)! - Improve schema options for linking authors to posts: | ||
- Add `inlineConnect: true` to the post's relationship to users | ||
- Remove authors from being inline-creatable | ||
|
||
* [#319](https://github.com/keystonejs/create-keystone-app/pull/319) [`94a859e`](https://github.com/keystonejs/create-keystone-app/commit/94a859e43123d2f348d5e21551d59bd7e257aa81) Thanks [@Achisingh](https://github.com/Achisingh)! - Fix dependencies and update schemas for the latest `keystone-6` release |
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 '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 }; |
Oops, something went wrong.