@checkstack/scripts 0.0.2
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/CHANGELOG.md +7 -0
- package/package.json +21 -0
- package/src/cli.ts +56 -0
- package/src/commands/create.ts +259 -0
- package/src/sync.ts +125 -0
- package/src/templates/backend/.changeset/initial.md.hbs +5 -0
- package/src/templates/backend/README.md.hbs +46 -0
- package/src/templates/backend/drizzle.config.ts.hbs +10 -0
- package/src/templates/backend/package.json.hbs +11 -0
- package/src/templates/backend/src/index.ts.hbs +35 -0
- package/src/templates/backend/src/router.ts.hbs +46 -0
- package/src/templates/backend/src/schema.ts.hbs +19 -0
- package/src/templates/backend/src/service.ts.hbs +69 -0
- package/src/templates/backend/tsconfig.json +6 -0
- package/src/templates/common/.changeset/initial.md.hbs +5 -0
- package/src/templates/common/README.md.hbs +11 -0
- package/src/templates/common/package.json.hbs +7 -0
- package/src/templates/common/src/index.ts.hbs +14 -0
- package/src/templates/common/src/permissions.ts.hbs +17 -0
- package/src/templates/common/src/plugin-metadata.ts.hbs +6 -0
- package/src/templates/common/src/routes.ts.hbs +6 -0
- package/src/templates/common/src/rpc-contract.ts.hbs +60 -0
- package/src/templates/common/src/schemas.ts.hbs +25 -0
- package/src/templates/common/tsconfig.json +6 -0
- package/src/templates/frontend/.changeset/initial.md.hbs +5 -0
- package/src/templates/frontend/README.md.hbs +29 -0
- package/src/templates/frontend/bunfig.toml.hbs +1 -0
- package/src/templates/frontend/package.json.hbs +12 -0
- package/src/templates/frontend/playwright.config.ts.hbs +3 -0
- package/src/templates/frontend/src/api.ts.hbs +15 -0
- package/src/templates/frontend/src/components/{{pluginNamePascal}}ListPage.tsx.hbs +81 -0
- package/src/templates/frontend/src/index.tsx.hbs +33 -0
- package/src/templates/frontend/tsconfig.json.hbs +1 -0
- package/src/templates/node/.changeset/initial.md.hbs +5 -0
- package/src/templates/node/README.md.hbs +8 -0
- package/src/templates/node/package.json.hbs +3 -0
- package/src/templates/node/src/index.ts.hbs +6 -0
- package/src/templates/node/tsconfig.json +6 -0
- package/src/templates/react/.changeset/initial.md.hbs +5 -0
- package/src/templates/react/README.md.hbs +23 -0
- package/src/templates/react/package.json.hbs +4 -0
- package/src/templates/react/src/components/{{pluginNamePascal}}Component.tsx.hbs +12 -0
- package/src/templates/react/src/index.tsx.hbs +1 -0
- package/src/templates/react/tsconfig.json +6 -0
- package/src/templates.test.ts +134 -0
- package/src/utils/template.ts +154 -0
- package/src/utils/validation.ts +110 -0
- package/tsconfig.json +6 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
2
|
+
import { eq } from "drizzle-orm";
|
|
3
|
+
import * as schema from "./schema";
|
|
4
|
+
import { {{pluginNameCamel}}Items } from "./schema";
|
|
5
|
+
import type {
|
|
6
|
+
Create{{pluginNamePascal}}Item,
|
|
7
|
+
Update{{pluginNamePascal}}Item,
|
|
8
|
+
} from "@checkstack/{{pluginBaseName}}-common";
|
|
9
|
+
|
|
10
|
+
export class {{pluginNamePascal}}Service {
|
|
11
|
+
constructor(private readonly database: NodePgDatabase<typeof schema>) {}
|
|
12
|
+
|
|
13
|
+
async getItems() {
|
|
14
|
+
return await this.database.select().from({{pluginNameCamel}}Items);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async getItem(id: string) {
|
|
18
|
+
const [item] = await this.database
|
|
19
|
+
.select()
|
|
20
|
+
.from({{pluginNameCamel}}Items)
|
|
21
|
+
.where(eq({{pluginNameCamel}}Items.id, id));
|
|
22
|
+
|
|
23
|
+
if (!item) {
|
|
24
|
+
throw new Error(`Item with id ${id} not found`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return item;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async createItem(data: Create{{pluginNamePascal}}Item) {
|
|
31
|
+
const [item] = await this.database
|
|
32
|
+
.insert({{pluginNameCamel}}Items)
|
|
33
|
+
.values({
|
|
34
|
+
name: data.name,
|
|
35
|
+
description: data.description,
|
|
36
|
+
})
|
|
37
|
+
.returning();
|
|
38
|
+
|
|
39
|
+
if (!item) {
|
|
40
|
+
throw new Error("Failed to create item");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return item;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async updateItem(id: string, data: Update{{pluginNamePascal}}Item) {
|
|
47
|
+
const [item] = await this.database
|
|
48
|
+
.update({{pluginNameCamel}}Items)
|
|
49
|
+
.set({
|
|
50
|
+
name: data.name,
|
|
51
|
+
description: data.description,
|
|
52
|
+
updatedAt: new Date(),
|
|
53
|
+
})
|
|
54
|
+
.where(eq({{pluginNameCamel}}Items.id, id))
|
|
55
|
+
.returning();
|
|
56
|
+
|
|
57
|
+
if (!item) {
|
|
58
|
+
throw new Error(`Item with id ${id} not found`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return item;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async deleteItem(id: string) {
|
|
65
|
+
await this.database
|
|
66
|
+
.delete({{pluginNameCamel}}Items)
|
|
67
|
+
.where(eq({{pluginNameCamel}}Items.id, id));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#
|
|
2
|
+
{{pluginNamePascal}}
|
|
3
|
+
Common Common package for the
|
|
4
|
+
{{pluginNamePascal}}
|
|
5
|
+
plugin. Contains shared contracts, types, and permissions. ## Structure -
|
|
6
|
+
`src/permissions.ts` - Permission definitions - `src/schemas.ts` - Zod schemas
|
|
7
|
+
and type definitions - `src/rpc-contract.ts` - oRPC contract definition -
|
|
8
|
+
`src/index.ts` - Barrel exports ## Usage This package is consumed by both: -
|
|
9
|
+
`@checkstack/{{pluginBaseName}}-backend` - Implements the contract -
|
|
10
|
+
`@checkstack/{{pluginBaseName}}-frontend` - Consumes the contract ##
|
|
11
|
+
Development ```bash # Type check bun run typecheck # Lint bun run lint ```
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{ "name": "@checkstack/{{pluginName}}", "version": "0.0.1",
|
|
2
|
+
"description": "{{pluginDescription}}", "type": "module", "exports": { ".": {
|
|
3
|
+
"import": "./src/index.ts" } }, "scripts": { "typecheck": "tsc --noEmit",
|
|
4
|
+
"lint": "bun run lint:code", "lint:code": "eslint . --max-warnings 0" },
|
|
5
|
+
"dependencies": { "@checkstack/common": "workspace:*", "@orpc/contract":
|
|
6
|
+
"^1.13.2", "zod": "^3.23.0" }, "devDependencies": {
|
|
7
|
+
"@checkstack/tsconfig": "workspace:*", "typescript": "^5.7.2" } }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Export permissions
|
|
2
|
+
export { permissions, permissionList } from "./permissions";
|
|
3
|
+
|
|
4
|
+
// Export routes
|
|
5
|
+
export { {{pluginNameCamel}}Routes } from "./routes";
|
|
6
|
+
|
|
7
|
+
// Export schemas and types
|
|
8
|
+
export * from "./schemas";
|
|
9
|
+
|
|
10
|
+
// Export plugin metadata
|
|
11
|
+
export * from "./plugin-metadata";
|
|
12
|
+
|
|
13
|
+
// Export contract and client definition
|
|
14
|
+
export { {{pluginNameCamel}}Contract, {{pluginNamePascal}}Api, type {{pluginNamePascal}}Contract } from "./rpc-contract";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createPermission } from "@checkstack/common";
|
|
2
|
+
|
|
3
|
+
export const permissions = {
|
|
4
|
+
{{pluginNameCamel}}Read: createPermission(
|
|
5
|
+
"{{pluginBaseName}}",
|
|
6
|
+
"read",
|
|
7
|
+
"Read {{pluginBaseName}} data",
|
|
8
|
+
{ isAuthenticatedDefault: true } // Auto-assigned to "users" role
|
|
9
|
+
),
|
|
10
|
+
{{pluginNameCamel}}Manage: createPermission(
|
|
11
|
+
"{{pluginBaseName}}",
|
|
12
|
+
"manage",
|
|
13
|
+
"Manage {{pluginBaseName}} data"
|
|
14
|
+
),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const permissionList = Object.values(permissions);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { definePluginMetadata } from "@checkstack/common"; /** * Plugin
|
|
2
|
+
metadata for the
|
|
3
|
+
{{pluginNamePascal}}
|
|
4
|
+
plugin. * Exported from the common package so both backend and frontend can *
|
|
5
|
+
reference it. */ export const pluginMetadata = definePluginMetadata({ pluginId:
|
|
6
|
+
"{{pluginId}}", });
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createRoutes } from "@checkstack/common"; /** * Route
|
|
2
|
+
definitions for the
|
|
3
|
+
{{pluginBaseName}}
|
|
4
|
+
plugin. * Use these for type-safe route generation with resolveRoute(). */
|
|
5
|
+
export const
|
|
6
|
+
{{pluginNameCamel}}Routes = createRoutes("{{pluginBaseName}}", { home: "/", });
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract";
|
|
2
|
+
import { createClientDefinition, type ProcedureMetadata } from "@checkstack/common";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import {
|
|
5
|
+
{{pluginNamePascal}}ItemSchema,
|
|
6
|
+
Create{{pluginNamePascal}}ItemSchema,
|
|
7
|
+
Update{{pluginNamePascal}}ItemSchema,
|
|
8
|
+
} from "./schemas";
|
|
9
|
+
import { permissions } from "./permissions";
|
|
10
|
+
import { pluginMetadata } from "./plugin-metadata";
|
|
11
|
+
|
|
12
|
+
// Create base builder with ProcedureMetadata support
|
|
13
|
+
// See: https://docs.checkstack.dev/common-plugins#contract-based-auth-enforcement
|
|
14
|
+
const _base = oc.$meta<ProcedureMetadata>({});
|
|
15
|
+
|
|
16
|
+
export const {{pluginNameCamel}}Contract = {
|
|
17
|
+
// List all items - requires authenticated user with read permission
|
|
18
|
+
getItems: _base
|
|
19
|
+
.meta({ userType: "user", permissions: [permissions.{{pluginNameCamel}}Read.id] })
|
|
20
|
+
.output(z.array({{pluginNamePascal}}ItemSchema)),
|
|
21
|
+
|
|
22
|
+
// Get single item
|
|
23
|
+
getItem: _base
|
|
24
|
+
.meta({ userType: "user", permissions: [permissions.{{pluginNameCamel}}Read.id] })
|
|
25
|
+
.input(z.string())
|
|
26
|
+
.output({{pluginNamePascal}}ItemSchema),
|
|
27
|
+
|
|
28
|
+
// Create item
|
|
29
|
+
createItem: _base
|
|
30
|
+
.meta({ userType: "user", permissions: [permissions.{{pluginNameCamel}}Manage.id] })
|
|
31
|
+
.input(Create{{pluginNamePascal}}ItemSchema)
|
|
32
|
+
.output({{pluginNamePascal}}ItemSchema),
|
|
33
|
+
|
|
34
|
+
// Update item
|
|
35
|
+
updateItem: _base
|
|
36
|
+
.meta({ userType: "user", permissions: [permissions.{{pluginNameCamel}}Manage.id] })
|
|
37
|
+
.input(
|
|
38
|
+
z.object({
|
|
39
|
+
id: z.string(),
|
|
40
|
+
data: Update{{pluginNamePascal}}ItemSchema,
|
|
41
|
+
})
|
|
42
|
+
)
|
|
43
|
+
.output({{pluginNamePascal}}ItemSchema),
|
|
44
|
+
|
|
45
|
+
// Delete item
|
|
46
|
+
deleteItem: _base
|
|
47
|
+
.meta({ userType: "user", permissions: [permissions.{{pluginNameCamel}}Manage.id] })
|
|
48
|
+
.input(z.string())
|
|
49
|
+
.output(z.void()),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Export contract type
|
|
53
|
+
export type {{pluginNamePascal}}Contract = typeof {{pluginNameCamel}}Contract;
|
|
54
|
+
|
|
55
|
+
// Export client definition for type-safe forPlugin usage
|
|
56
|
+
// Use: const client = rpcApi.forPlugin({{pluginNamePascal}}Api);
|
|
57
|
+
export const {{pluginNamePascal}}Api = createClientDefinition(
|
|
58
|
+
{{pluginNameCamel}}Contract,
|
|
59
|
+
pluginMetadata
|
|
60
|
+
);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// Example schema - customize for your domain
|
|
4
|
+
export const {{pluginNamePascal}}ItemSchema = z.object({
|
|
5
|
+
id: z.string(),
|
|
6
|
+
name: z.string(),
|
|
7
|
+
description: z.string().nullable(),
|
|
8
|
+
createdAt: z.date(),
|
|
9
|
+
updatedAt: z.date(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type {{pluginNamePascal}}Item = z.infer<typeof {{pluginNamePascal}}ItemSchema>;
|
|
13
|
+
|
|
14
|
+
// Input schema for creating items (omit id and timestamps)
|
|
15
|
+
export const Create{{pluginNamePascal}}ItemSchema = z.object({
|
|
16
|
+
name: z.string().min(1).max(255),
|
|
17
|
+
description: z.string().optional(),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export type Create{{pluginNamePascal}}Item = z.infer<typeof Create{{pluginNamePascal}}ItemSchema>;
|
|
21
|
+
|
|
22
|
+
// Input schema for updating items
|
|
23
|
+
export const Update{{pluginNamePascal}}ItemSchema = Create{{pluginNamePascal}}ItemSchema.partial();
|
|
24
|
+
|
|
25
|
+
export type Update{{pluginNamePascal}}Item = z.infer<typeof Update{{pluginNamePascal}}ItemSchema>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# {{pluginNamePascal}} Frontend
|
|
2
|
+
|
|
3
|
+
Frontend plugin for {{pluginNamePascal}}. Provides UI components and pages.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
- `src/index.tsx` - Plugin entry point
|
|
8
|
+
- `src/api.ts` - Contract-based API definition
|
|
9
|
+
- `src/components/` - React components
|
|
10
|
+
|
|
11
|
+
## Development
|
|
12
|
+
|
|
13
|
+
### Type Check
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun run typecheck
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Lint
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
bun run lint
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Testing
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bun test
|
|
29
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[test] preload = ["@checkstack/test-utils-frontend/setup"]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{ "name": "@checkstack/{{pluginName}}", "version": "0.0.1",
|
|
2
|
+
"description": "{{pluginDescription}}", "type": "module", "exports": { ".": {
|
|
3
|
+
"import": "./src/index.tsx" } }, "scripts": { "typecheck": "tsc --noEmit",
|
|
4
|
+
"lint": "bun run lint:code", "lint:code": "eslint . --max-warnings 0",
|
|
5
|
+
"test:e2e": "bunx playwright test" }, "dependencies": {
|
|
6
|
+
"@checkstack/frontend-api": "workspace:*", "@checkstack/common":
|
|
7
|
+
"workspace:*", "@checkstack/{{pluginBaseName}}-common": "workspace:*",
|
|
8
|
+
"@checkstack/ui": "workspace:*", "react": "^18.3.1", "react-router-dom":
|
|
9
|
+
"^7.1.1", "lucide-react": "^0.469.0" }, "devDependencies": {
|
|
10
|
+
"@checkstack/tsconfig": "workspace:*", "@types/react": "^18.3.1",
|
|
11
|
+
"@playwright/test": "^1.49.0", "@checkstack/test-utils-frontend":
|
|
12
|
+
"workspace:*", "typescript": "^5.7.2" } }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createApiRef } from "@checkstack/frontend-api";
|
|
2
|
+
import type { InferClient } from "@checkstack/common";
|
|
3
|
+
import { {{pluginNamePascal}}Api } from "@checkstack/{{pluginBaseName}}-common";
|
|
4
|
+
|
|
5
|
+
// Re-export types for convenience
|
|
6
|
+
export type {
|
|
7
|
+
{{pluginNamePascal}}Item,
|
|
8
|
+
Create{{pluginNamePascal}}Item,
|
|
9
|
+
Update{{pluginNamePascal}}Item,
|
|
10
|
+
} from "@checkstack/{{pluginBaseName}}-common";
|
|
11
|
+
|
|
12
|
+
// {{pluginNamePascal}}ApiClient is the client type inferred from the Api definition
|
|
13
|
+
export type {{pluginNamePascal}}ApiClient = InferClient<typeof {{pluginNamePascal}}Api>;
|
|
14
|
+
|
|
15
|
+
export const {{pluginNameCamel}}ApiRef = createApiRef<{{pluginNamePascal}}ApiClient>("{{pluginBaseName}}-api");
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { useApi } from "@checkstack/frontend-api";
|
|
3
|
+
import { {{pluginNameCamel}}ApiRef, type {{pluginNamePascal}}Item } from "../api";
|
|
4
|
+
import { Button, Card } from "@checkstack/ui";
|
|
5
|
+
import { useNavigate } from "react-router-dom";
|
|
6
|
+
|
|
7
|
+
export const {{pluginNamePascal}}ListPage = () => {
|
|
8
|
+
const api = useApi({{pluginNameCamel}}ApiRef);
|
|
9
|
+
const navigate = useNavigate();
|
|
10
|
+
const [items, setItems] = useState<{{pluginNamePascal}}Item[]>([]);
|
|
11
|
+
const [loading, setLoading] = useState(true);
|
|
12
|
+
const [error, setError] = useState<Error>();
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
api
|
|
16
|
+
.getItems()
|
|
17
|
+
.then(setItems)
|
|
18
|
+
.catch(setError)
|
|
19
|
+
.finally(() => setLoading(false));
|
|
20
|
+
}, [api]);
|
|
21
|
+
|
|
22
|
+
const handleDelete = async (id: string) => {
|
|
23
|
+
try {
|
|
24
|
+
await api.deleteItem(id);
|
|
25
|
+
setItems(items.filter((item) => item.id !== id));
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error("Failed to delete item:", error);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
if (loading) return <div className="p-6">Loading...</div>;
|
|
32
|
+
if (error) return <div className="p-6 text-red-500">Error: {error.message}</div>;
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div className="p-6">
|
|
36
|
+
<div className="flex justify-between items-center mb-4">
|
|
37
|
+
<h1 className="text-2xl font-bold">{{pluginNamePascal}} Items</h1>
|
|
38
|
+
<Button onClick={() => navigate("/{{pluginBaseName}}/new")}>
|
|
39
|
+
Create Item
|
|
40
|
+
</Button>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div className="grid gap-4">
|
|
44
|
+
{items.map((item) => (
|
|
45
|
+
<Card key={item.id} className="p-4">
|
|
46
|
+
<div className="flex justify-between items-start">
|
|
47
|
+
<div>
|
|
48
|
+
<h3 className="font-semibold">{item.name}</h3>
|
|
49
|
+
{item.description && (
|
|
50
|
+
<p className="text-sm text-gray-600">{item.description}</p>
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
<div className="flex gap-2">
|
|
54
|
+
<Button
|
|
55
|
+
variant="outline"
|
|
56
|
+
size="sm"
|
|
57
|
+
onClick={() => navigate(`/{{pluginBaseName}}/${item.id}`)}
|
|
58
|
+
>
|
|
59
|
+
View
|
|
60
|
+
</Button>
|
|
61
|
+
<Button
|
|
62
|
+
variant="destructive"
|
|
63
|
+
size="sm"
|
|
64
|
+
onClick={() => handleDelete(item.id)}
|
|
65
|
+
>
|
|
66
|
+
Delete
|
|
67
|
+
</Button>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</Card>
|
|
71
|
+
))}
|
|
72
|
+
|
|
73
|
+
{items.length === 0 && (
|
|
74
|
+
<Card className="p-8 text-center text-gray-500">
|
|
75
|
+
No items yet. Create your first item to get started.
|
|
76
|
+
</Card>
|
|
77
|
+
)}
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createFrontendPlugin, rpcApiRef, type ApiRef } from "@checkstack/frontend-api";
|
|
2
|
+
import { {{pluginNameCamel}}ApiRef, type {{pluginNamePascal}}ApiClient } from "./api";
|
|
3
|
+
import { {{pluginNamePascal}}ListPage } from "./components/{{pluginNamePascal}}ListPage";
|
|
4
|
+
import { {{pluginNameCamel}}Routes, {{pluginNamePascal}}Api, pluginMetadata, permissions } from "@checkstack/{{pluginBaseName}}-common";
|
|
5
|
+
|
|
6
|
+
export default createFrontendPlugin({
|
|
7
|
+
metadata: pluginMetadata,
|
|
8
|
+
|
|
9
|
+
// Register routes using typed route definitions
|
|
10
|
+
routes: [
|
|
11
|
+
{
|
|
12
|
+
route: {{pluginNameCamel}}Routes.routes.home,
|
|
13
|
+
element: <{{pluginNamePascal}}ListPage />,
|
|
14
|
+
title: "{{pluginNamePascal}}",
|
|
15
|
+
permission: permissions.{{pluginNameCamel}}Read,
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
|
|
19
|
+
// Register client API using oRPC
|
|
20
|
+
apis: [
|
|
21
|
+
{
|
|
22
|
+
ref: {{pluginNameCamel}}ApiRef,
|
|
23
|
+
factory: (deps: { get: <T>(ref: ApiRef<T>) => T }): {{pluginNamePascal}}ApiClient => {
|
|
24
|
+
const rpcApi = deps.get(rpcApiRef);
|
|
25
|
+
// Create type-safe client using the plugin's Api definition
|
|
26
|
+
return rpcApi.forPlugin({{pluginNamePascal}}Api);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export * from "./api";
|
|
33
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "extends": "@checkstack/tsconfig/frontend.json", "include": [ "src" ] }
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#
|
|
2
|
+
{{pluginNamePascal}}
|
|
3
|
+
|
|
4
|
+
{{pluginDescription}}
|
|
5
|
+
|
|
6
|
+
## Usage ```typescript import { hello{{pluginNamePascal}}
|
|
7
|
+
} from "@checkstack/{{pluginName}}"; console.log(hello{{pluginNamePascal}}());
|
|
8
|
+
``` ## Development ```bash bun run typecheck bun run lint bun test ```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# {{pluginNamePascal}}
|
|
2
|
+
|
|
3
|
+
{{pluginDescription}}
|
|
4
|
+
|
|
5
|
+
## Components
|
|
6
|
+
|
|
7
|
+
### {{pluginNamePascal}}Component
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { {{pluginNamePascal}}Component } from "@checkstack/{{pluginName}}";
|
|
11
|
+
|
|
12
|
+
function App() {
|
|
13
|
+
return <{{pluginNamePascal}}Component title="My Title" />;
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Development
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bun run typecheck
|
|
21
|
+
bun run lint
|
|
22
|
+
bun test
|
|
23
|
+
```
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
{ "name": "@checkstack/{{pluginName}}", "version": "0.0.1",
|
|
2
|
+
"description": "{{pluginDescription}}", "type": "module", "exports": { ".": {
|
|
3
|
+
"import": "./src/index.tsx" } }, "dependencies": { "react": "^18.3.1" },
|
|
4
|
+
"devDependencies": { "@types/react": "^18.3.1", "typescript": "^5.7.2" } }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface {{pluginNamePascal}}ComponentProps {
|
|
2
|
+
title?: string;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function {{pluginNamePascal}}Component({ title = "{{pluginNamePascal}}" }: {{pluginNamePascal}}ComponentProps) {
|
|
6
|
+
return (
|
|
7
|
+
<div>
|
|
8
|
+
<h1>{title}</h1>
|
|
9
|
+
<p>This is a {{pluginNamePascal}} component.</p>
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { {{pluginNamePascal}}Component } from "./components/{{pluginNamePascal}}Component";
|