create-faas-app 8.0.0-beta.3 → 8.0.0-beta.30
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/README.md +66 -9
- package/dist/index.d.ts +11 -16
- package/dist/index.mjs +147 -153
- package/index.mjs +1 -1
- package/package.json +20 -23
- package/template/admin/.env.example +1 -0
- package/template/admin/gitignore +4 -0
- package/template/admin/index.html +12 -0
- package/template/admin/migrations/20250101000000_create_users.ts +12 -0
- package/template/admin/package.json +34 -0
- package/template/admin/server.ts +33 -0
- package/template/admin/src/faas.yaml +11 -0
- package/template/admin/src/main.tsx +25 -0
- package/template/admin/src/pages/home/api/auth/__tests__/me.test.ts +39 -0
- package/template/admin/src/pages/home/api/auth/me.api.ts +23 -0
- package/template/admin/src/pages/home/api/users/__tests__/create.test.ts +47 -0
- package/template/admin/src/pages/home/api/users/__tests__/detail.test.ts +39 -0
- package/template/admin/src/pages/home/api/users/__tests__/list.test.ts +31 -0
- package/template/admin/src/pages/home/api/users/__tests__/update.test.ts +51 -0
- package/template/admin/src/pages/home/api/users/create.api.ts +26 -0
- package/template/admin/src/pages/home/api/users/detail.api.ts +23 -0
- package/template/admin/src/pages/home/api/users/list.api.ts +22 -0
- package/template/admin/src/pages/home/api/users/update.api.ts +35 -0
- package/template/admin/src/pages/home/index.tsx +163 -0
- package/template/admin/src/plugins/auth.ts +25 -0
- package/template/admin/src/types/faasjs-auth.d.ts +8 -0
- package/template/admin/src/types/faasjs-pg.d.ts +10 -0
- package/template/admin/tsconfig.json +4 -0
- package/template/admin/vite.config.ts +12 -0
- package/template/minimal/gitignore +4 -0
- package/template/minimal/index.html +12 -0
- package/template/minimal/package.json +26 -0
- package/template/minimal/server.ts +33 -0
- package/template/minimal/src/faas.yaml +11 -0
- package/template/minimal/src/main.tsx +5 -0
- package/template/minimal/src/pages/home/api/__tests__/hello.test.ts +17 -0
- package/template/minimal/src/pages/home/api/hello.api.ts +13 -0
- package/template/minimal/src/pages/home/index.tsx +46 -0
- package/template/minimal/src/react-client.ts +8 -0
- package/template/minimal/tsconfig.json +4 -0
- package/template/minimal/vite.config.ts +6 -0
- package/dist/index.cjs +0 -164
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { testApi } from '@faasjs/dev'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import api from '../me.api'
|
|
5
|
+
|
|
6
|
+
describe('pages/home/api/auth/me', () => {
|
|
7
|
+
it('returns the current user from the auth plugin demo', async () => {
|
|
8
|
+
const handler = testApi(api)
|
|
9
|
+
|
|
10
|
+
const { statusCode, data } = await handler(
|
|
11
|
+
{},
|
|
12
|
+
{
|
|
13
|
+
headers: {
|
|
14
|
+
authorization: 'Bearer demo-admin',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
expect(statusCode).toEqual(200)
|
|
20
|
+
expect(data).toEqual({
|
|
21
|
+
current_user: {
|
|
22
|
+
id: 1,
|
|
23
|
+
name: 'Demo Admin',
|
|
24
|
+
role: 'admin',
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('rejects requests without the demo token', async () => {
|
|
30
|
+
const handler = testApi(api)
|
|
31
|
+
|
|
32
|
+
const { statusCode, error } = await handler()
|
|
33
|
+
|
|
34
|
+
expect(statusCode).toEqual(401)
|
|
35
|
+
expect(error).toEqual({
|
|
36
|
+
message: 'Missing demo auth token',
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineApi, HttpError } from '@faasjs/core'
|
|
2
|
+
import { z } from '@faasjs/utils'
|
|
3
|
+
|
|
4
|
+
import { AuthPlugin } from '../../../../plugins/auth'
|
|
5
|
+
|
|
6
|
+
const api = defineApi({
|
|
7
|
+
schema: z.object({}).strict(),
|
|
8
|
+
async handler({ current_user }) {
|
|
9
|
+
if (!current_user)
|
|
10
|
+
throw new HttpError({
|
|
11
|
+
statusCode: 401,
|
|
12
|
+
message: 'Missing demo auth token',
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
current_user,
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
api.plugins.unshift(new AuthPlugin())
|
|
22
|
+
|
|
23
|
+
export default api
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { testApi } from '@faasjs/dev'
|
|
2
|
+
import { getClient } from '@faasjs/pg'
|
|
3
|
+
import { describe, expect, it } from 'vitest'
|
|
4
|
+
|
|
5
|
+
import api from '../create.api'
|
|
6
|
+
|
|
7
|
+
describe('pages/home/api/users/create', () => {
|
|
8
|
+
it('creates a user with the shared pg bootstrap', async () => {
|
|
9
|
+
const handler = testApi(api)
|
|
10
|
+
|
|
11
|
+
const { statusCode, data } = await handler({ name: 'world' })
|
|
12
|
+
|
|
13
|
+
expect(statusCode).toEqual(200)
|
|
14
|
+
expect(data).toEqual({
|
|
15
|
+
message: 'Created user #1',
|
|
16
|
+
total: 1,
|
|
17
|
+
user: {
|
|
18
|
+
id: 1,
|
|
19
|
+
name: 'world',
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const client = await getClient()
|
|
24
|
+
|
|
25
|
+
await expect(client.query('users').orderBy('id', 'ASC')).resolves.toEqual([
|
|
26
|
+
{
|
|
27
|
+
id: 1,
|
|
28
|
+
name: 'world',
|
|
29
|
+
},
|
|
30
|
+
])
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('uses the default name when params.name is missing', async () => {
|
|
34
|
+
const handler = testApi(api)
|
|
35
|
+
|
|
36
|
+
const { data } = await handler({})
|
|
37
|
+
|
|
38
|
+
expect(data).toEqual({
|
|
39
|
+
message: 'Created user #1',
|
|
40
|
+
total: 1,
|
|
41
|
+
user: {
|
|
42
|
+
id: 1,
|
|
43
|
+
name: 'FaasJS',
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { testApi } from '@faasjs/dev'
|
|
2
|
+
import { getClient } from '@faasjs/pg'
|
|
3
|
+
import { describe, expect, it } from 'vitest'
|
|
4
|
+
|
|
5
|
+
import api from '../detail.api'
|
|
6
|
+
|
|
7
|
+
describe('pages/home/api/users/detail', () => {
|
|
8
|
+
it('returns one user', async () => {
|
|
9
|
+
const client = await getClient()
|
|
10
|
+
const [created] = await client.query('users').insert(
|
|
11
|
+
{
|
|
12
|
+
name: 'Ada',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
returning: ['id'],
|
|
16
|
+
},
|
|
17
|
+
)
|
|
18
|
+
const handler = testApi(api)
|
|
19
|
+
const { statusCode, data } = await handler({ id: created.id })
|
|
20
|
+
|
|
21
|
+
expect(statusCode).toEqual(200)
|
|
22
|
+
expect(data).toEqual({
|
|
23
|
+
user: {
|
|
24
|
+
id: created.id,
|
|
25
|
+
name: 'Ada',
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('returns 404 when the user is missing', async () => {
|
|
31
|
+
const handler = testApi(api)
|
|
32
|
+
const { statusCode, error } = await handler({ id: 404 })
|
|
33
|
+
|
|
34
|
+
expect(statusCode).toEqual(404)
|
|
35
|
+
expect(error).toEqual({
|
|
36
|
+
message: 'User not found',
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { testApi } from '@faasjs/dev'
|
|
2
|
+
import { getClient } from '@faasjs/pg'
|
|
3
|
+
import { describe, expect, it } from 'vitest'
|
|
4
|
+
|
|
5
|
+
import api from '../list.api'
|
|
6
|
+
|
|
7
|
+
describe('pages/home/api/users/list', () => {
|
|
8
|
+
it('lists users with total count', async () => {
|
|
9
|
+
const client = await getClient()
|
|
10
|
+
|
|
11
|
+
await client.query('users').insert([{ name: 'Ada' }, { name: 'Grace' }])
|
|
12
|
+
|
|
13
|
+
const handler = testApi(api)
|
|
14
|
+
const { statusCode, data } = await handler({ limit: 10 })
|
|
15
|
+
|
|
16
|
+
expect(statusCode).toEqual(200)
|
|
17
|
+
expect(data).toEqual({
|
|
18
|
+
total: 2,
|
|
19
|
+
rows: [
|
|
20
|
+
{
|
|
21
|
+
id: 2,
|
|
22
|
+
name: 'Grace',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 1,
|
|
26
|
+
name: 'Ada',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { testApi } from '@faasjs/dev'
|
|
2
|
+
import { getClient } from '@faasjs/pg'
|
|
3
|
+
import { describe, expect, it } from 'vitest'
|
|
4
|
+
|
|
5
|
+
import api from '../update.api'
|
|
6
|
+
|
|
7
|
+
describe('pages/home/api/users/update', () => {
|
|
8
|
+
it('updates one user', async () => {
|
|
9
|
+
const client = await getClient()
|
|
10
|
+
const [created] = await client.query('users').insert(
|
|
11
|
+
{
|
|
12
|
+
name: 'Ada',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
returning: ['id'],
|
|
16
|
+
},
|
|
17
|
+
)
|
|
18
|
+
const handler = testApi(api)
|
|
19
|
+
const { statusCode, data } = await handler({
|
|
20
|
+
id: created.id,
|
|
21
|
+
name: 'Ada Lovelace',
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
expect(statusCode).toEqual(200)
|
|
25
|
+
expect(data).toEqual({
|
|
26
|
+
message: `Updated user #${created.id}`,
|
|
27
|
+
user: {
|
|
28
|
+
id: created.id,
|
|
29
|
+
name: 'Ada Lovelace',
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
await expect(client.query('users').where('id', created.id).first()).resolves.toEqual({
|
|
34
|
+
id: created.id,
|
|
35
|
+
name: 'Ada Lovelace',
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('returns 404 when the user is missing', async () => {
|
|
40
|
+
const handler = testApi(api)
|
|
41
|
+
const { statusCode, error } = await handler({
|
|
42
|
+
id: 404,
|
|
43
|
+
name: 'Missing',
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
expect(statusCode).toEqual(404)
|
|
47
|
+
expect(error).toEqual({
|
|
48
|
+
message: 'User not found',
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { defineApi } from '@faasjs/core'
|
|
2
|
+
import { getClient } from '@faasjs/pg'
|
|
3
|
+
import { z } from '@faasjs/utils'
|
|
4
|
+
|
|
5
|
+
export default defineApi({
|
|
6
|
+
schema: z.object({
|
|
7
|
+
name: z.nonemptystring().optional(),
|
|
8
|
+
}),
|
|
9
|
+
async handler({ params }) {
|
|
10
|
+
const client = await getClient()
|
|
11
|
+
const [user] = await client.query('users').insert(
|
|
12
|
+
{
|
|
13
|
+
name: params.name || 'FaasJS',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
returning: ['id', 'name'],
|
|
17
|
+
},
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
message: `Created user #${user.id}`,
|
|
22
|
+
total: await client.query('users').count(),
|
|
23
|
+
user,
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineApi, HttpError } from '@faasjs/core'
|
|
2
|
+
import { getClient } from '@faasjs/pg'
|
|
3
|
+
import { z } from '@faasjs/utils'
|
|
4
|
+
|
|
5
|
+
export default defineApi({
|
|
6
|
+
schema: z.object({
|
|
7
|
+
id: z.positiveint(),
|
|
8
|
+
}),
|
|
9
|
+
async handler({ params }) {
|
|
10
|
+
const client = await getClient()
|
|
11
|
+
const user = await client.query('users').select('id', 'name').where('id', params.id).first()
|
|
12
|
+
|
|
13
|
+
if (!user)
|
|
14
|
+
throw new HttpError({
|
|
15
|
+
statusCode: 404,
|
|
16
|
+
message: 'User not found',
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
user,
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineApi } from '@faasjs/core'
|
|
2
|
+
import { getClient } from '@faasjs/pg'
|
|
3
|
+
import { z } from '@faasjs/utils'
|
|
4
|
+
|
|
5
|
+
export default defineApi({
|
|
6
|
+
schema: z.object({
|
|
7
|
+
limit: z.positiveint().max(50).default(20),
|
|
8
|
+
}),
|
|
9
|
+
async handler({ params }) {
|
|
10
|
+
const client = await getClient()
|
|
11
|
+
const users = await client
|
|
12
|
+
.query('users')
|
|
13
|
+
.select('id', 'name')
|
|
14
|
+
.orderBy('id', 'DESC')
|
|
15
|
+
.limit(params.limit)
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
total: await client.query('users').count(),
|
|
19
|
+
rows: users,
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { defineApi, HttpError } from '@faasjs/core'
|
|
2
|
+
import { getClient } from '@faasjs/pg'
|
|
3
|
+
import { z } from '@faasjs/utils'
|
|
4
|
+
|
|
5
|
+
export default defineApi({
|
|
6
|
+
schema: z.object({
|
|
7
|
+
id: z.positiveint(),
|
|
8
|
+
name: z.nonemptystring(),
|
|
9
|
+
}),
|
|
10
|
+
async handler({ params }) {
|
|
11
|
+
const client = await getClient()
|
|
12
|
+
const [user] = await client
|
|
13
|
+
.query('users')
|
|
14
|
+
.where('id', params.id)
|
|
15
|
+
.update(
|
|
16
|
+
{
|
|
17
|
+
name: params.name,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
returning: ['id', 'name'],
|
|
21
|
+
},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
if (!user)
|
|
25
|
+
throw new HttpError({
|
|
26
|
+
statusCode: 404,
|
|
27
|
+
message: 'User not found',
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
message: `Updated user #${user.id}`,
|
|
32
|
+
user,
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
})
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
declare module '@faasjs/types' {
|
|
2
|
+
interface FaasActions {
|
|
3
|
+
'/pages/home/api/users/list': {
|
|
4
|
+
Params: { limit: number }
|
|
5
|
+
Data: { total?: number; rows?: { id: number; name: string }[] }
|
|
6
|
+
}
|
|
7
|
+
'/pages/home/api/users/create': {
|
|
8
|
+
Params: { name?: string | undefined }
|
|
9
|
+
Data: { message?: string; total?: number; user?: { id: number; name: string } }
|
|
10
|
+
}
|
|
11
|
+
'/pages/home/api/users/update': {
|
|
12
|
+
Params: { id: number; name: string }
|
|
13
|
+
Data: { message?: string; user?: { id: number; name: string } }
|
|
14
|
+
}
|
|
15
|
+
'/pages/home/api/users/detail': {
|
|
16
|
+
Params: { id: number }
|
|
17
|
+
Data: { user?: { id: number; name: string } }
|
|
18
|
+
}
|
|
19
|
+
'/pages/home/api/auth/me': {
|
|
20
|
+
Params: Record<string, never>
|
|
21
|
+
Data: { current_user?: { id: number; name: string; role: string } }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
import { faas, useApp } from '@faasjs/ant-design'
|
|
27
|
+
import { useFaas } from '@faasjs/react'
|
|
28
|
+
import { Button, Card, Input, Space, Table, Typography } from 'antd'
|
|
29
|
+
import { useState } from 'react'
|
|
30
|
+
|
|
31
|
+
export default function HomePage() {
|
|
32
|
+
const app = useApp()
|
|
33
|
+
const [name, setName] = useState('FaasJS')
|
|
34
|
+
const [messageText, setMessageText] = useState('Create your first user through the FaasJS API')
|
|
35
|
+
|
|
36
|
+
const {
|
|
37
|
+
data: listData,
|
|
38
|
+
loading: listLoading,
|
|
39
|
+
reload,
|
|
40
|
+
} = useFaas('/pages/home/api/users/list', { limit: 10 })
|
|
41
|
+
|
|
42
|
+
const rows = listData?.rows || []
|
|
43
|
+
|
|
44
|
+
const [creating, setCreating] = useState(false)
|
|
45
|
+
const callApi = async () => {
|
|
46
|
+
setCreating(true)
|
|
47
|
+
try {
|
|
48
|
+
const response = await faas('/pages/home/api/users/create', {
|
|
49
|
+
name: name.trim() || undefined,
|
|
50
|
+
})
|
|
51
|
+
const result = response.data
|
|
52
|
+
const nextMessage =
|
|
53
|
+
result?.user && typeof result.total === 'number'
|
|
54
|
+
? `Created ${result.user.name} (#${result.user.id}). Total users: ${result.total}`
|
|
55
|
+
: result?.message || 'Empty response'
|
|
56
|
+
|
|
57
|
+
setMessageText(nextMessage)
|
|
58
|
+
app.message.success('User saved to PostgreSQL')
|
|
59
|
+
reload()
|
|
60
|
+
} catch (error: unknown) {
|
|
61
|
+
const errorMessage = error instanceof Error ? error.message : 'Request failed'
|
|
62
|
+
setMessageText(errorMessage)
|
|
63
|
+
app.notification.error({
|
|
64
|
+
message: 'API call failed',
|
|
65
|
+
description: errorMessage,
|
|
66
|
+
})
|
|
67
|
+
} finally {
|
|
68
|
+
setCreating(false)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const [authLoading, setAuthLoading] = useState(false)
|
|
73
|
+
const callAuthDemo = async () => {
|
|
74
|
+
setAuthLoading(true)
|
|
75
|
+
try {
|
|
76
|
+
const response = await faas(
|
|
77
|
+
'/pages/home/api/auth/me',
|
|
78
|
+
{},
|
|
79
|
+
{
|
|
80
|
+
headers: { authorization: 'Bearer demo-admin' },
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
const currentUser = response.data?.current_user
|
|
84
|
+
setMessageText(`Auth plugin injected current user: ${currentUser?.name || 'unknown'}`)
|
|
85
|
+
app.message.success('Auth plugin demo loaded current_user')
|
|
86
|
+
} catch (error: unknown) {
|
|
87
|
+
const errorMessage = error instanceof Error ? error.message : 'Auth demo failed'
|
|
88
|
+
setMessageText(errorMessage)
|
|
89
|
+
app.notification.error({
|
|
90
|
+
message: 'Auth demo failed',
|
|
91
|
+
description: errorMessage,
|
|
92
|
+
})
|
|
93
|
+
} finally {
|
|
94
|
+
setAuthLoading(false)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<div
|
|
100
|
+
style={{
|
|
101
|
+
minHeight: '100vh',
|
|
102
|
+
display: 'grid',
|
|
103
|
+
placeItems: 'center',
|
|
104
|
+
padding: 24,
|
|
105
|
+
background: 'linear-gradient(135deg, #f5f7fa 0%, #e4ecfb 100%)',
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
<Card
|
|
109
|
+
style={{
|
|
110
|
+
width: '100%',
|
|
111
|
+
maxWidth: 640,
|
|
112
|
+
boxShadow: '0 20px 45px rgba(15, 23, 42, 0.08)',
|
|
113
|
+
}}
|
|
114
|
+
>
|
|
115
|
+
<Space direction="vertical" size="large" style={{ width: '100%' }}>
|
|
116
|
+
<div>
|
|
117
|
+
<Typography.Title level={2}>FaasJS Admin App</Typography.Title>
|
|
118
|
+
<Typography.Paragraph type="secondary">
|
|
119
|
+
This starter follows the curated FaasJS path: React, Ant Design, PostgreSQL,
|
|
120
|
+
pg-dev-powered tests, and a simple auth plugin demo.
|
|
121
|
+
</Typography.Paragraph>
|
|
122
|
+
<Typography.Paragraph type="secondary">
|
|
123
|
+
Set <code>DATABASE_URL</code> from <code>.env.example</code> and run{' '}
|
|
124
|
+
<code>npm run db:migrate</code> before using the page in development.
|
|
125
|
+
</Typography.Paragraph>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<Input
|
|
129
|
+
value={name}
|
|
130
|
+
onChange={(event) => setName(event.target.value)}
|
|
131
|
+
placeholder="Who should the admin app create?"
|
|
132
|
+
/>
|
|
133
|
+
|
|
134
|
+
<Space wrap>
|
|
135
|
+
<Button onClick={() => reload()} loading={listLoading}>
|
|
136
|
+
Load users slice
|
|
137
|
+
</Button>
|
|
138
|
+
<Button type="primary" loading={creating} onClick={callApi}>
|
|
139
|
+
Create /pages/home/api/users/create
|
|
140
|
+
</Button>
|
|
141
|
+
<Button loading={authLoading} onClick={callAuthDemo}>
|
|
142
|
+
Call auth plugin demo
|
|
143
|
+
</Button>
|
|
144
|
+
</Space>
|
|
145
|
+
|
|
146
|
+
<Table
|
|
147
|
+
rowKey="id"
|
|
148
|
+
size="small"
|
|
149
|
+
pagination={false}
|
|
150
|
+
loading={listLoading}
|
|
151
|
+
dataSource={rows}
|
|
152
|
+
columns={[
|
|
153
|
+
{ title: 'ID', dataIndex: 'id' },
|
|
154
|
+
{ title: 'Name', dataIndex: 'name' },
|
|
155
|
+
]}
|
|
156
|
+
/>
|
|
157
|
+
|
|
158
|
+
<Typography.Paragraph style={{ marginBottom: 0 }}>{messageText}</Typography.Paragraph>
|
|
159
|
+
</Space>
|
|
160
|
+
</Card>
|
|
161
|
+
</div>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { InvokeData, Next, Plugin } from '@faasjs/core'
|
|
2
|
+
|
|
3
|
+
export type CurrentUser = {
|
|
4
|
+
id: number
|
|
5
|
+
name: string
|
|
6
|
+
role: 'admin'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class AuthPlugin implements Plugin {
|
|
10
|
+
public readonly name = 'auth'
|
|
11
|
+
public readonly type = 'auth'
|
|
12
|
+
|
|
13
|
+
public async onInvoke(data: InvokeData, next: Next): Promise<void> {
|
|
14
|
+
const token = data.event?.headers?.authorization || data.event?.headers?.Authorization
|
|
15
|
+
|
|
16
|
+
if (token === 'Bearer demo-admin')
|
|
17
|
+
data.current_user = {
|
|
18
|
+
id: 1,
|
|
19
|
+
name: 'Demo Admin',
|
|
20
|
+
role: 'admin',
|
|
21
|
+
} satisfies CurrentUser
|
|
22
|
+
|
|
23
|
+
await next()
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ViteConfig } from '@faasjs/dev'
|
|
2
|
+
import { PgVitestPlugin } from '@faasjs/pg-dev'
|
|
3
|
+
import { defineConfig } from 'vite-plus'
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
...ViteConfig,
|
|
7
|
+
plugins: [...ViteConfig.plugins, PgVitestPlugin()],
|
|
8
|
+
test: {
|
|
9
|
+
fileParallelism: false,
|
|
10
|
+
testTimeout: 30_000,
|
|
11
|
+
},
|
|
12
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>FaasJS App</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vp dev",
|
|
8
|
+
"build": "vp build",
|
|
9
|
+
"start": "node --import @faasjs/node-utils/register-hooks server.ts",
|
|
10
|
+
"test": "vp test"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@faasjs/dev": "*"
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"@faasjs/core": "*"
|
|
17
|
+
},
|
|
18
|
+
"overrides": {
|
|
19
|
+
"vite": "npm:@voidzero-dev/vite-plus-core",
|
|
20
|
+
"vitest": "npm:@voidzero-dev/vite-plus-test"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=26.0.0",
|
|
24
|
+
"npm": ">=11.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { dirname, join } from 'node:path'
|
|
2
|
+
import { loadEnvFile } from 'node:process'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
|
|
5
|
+
import { Server, staticHandler } from '@faasjs/core'
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
8
|
+
const __dirname = dirname(__filename)
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
loadEnvFile()
|
|
12
|
+
} catch (error) {
|
|
13
|
+
console.warn('[faasjs] Failed to load env file', error)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const publicHandler = staticHandler({
|
|
17
|
+
root: join(__dirname, 'public'),
|
|
18
|
+
notFound: false,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const distHandler = staticHandler({
|
|
22
|
+
root: join(__dirname, 'dist'),
|
|
23
|
+
notFound: 'index.html',
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
new Server(join(__dirname, 'src'), {
|
|
27
|
+
beforeHandle: async (req, res, ctx) => {
|
|
28
|
+
if (!req.url || req.method !== 'GET') return
|
|
29
|
+
|
|
30
|
+
await publicHandler(req, res, ctx)
|
|
31
|
+
await distHandler(req, res, ctx)
|
|
32
|
+
},
|
|
33
|
+
}).listen()
|