93 |
├── genclient
├── utils.go
├── typescript
│ └── generator.go
├── gendoc_test.go
├── testdata
│ ├── gendoctest
│ │ ├── tsconfig.json
│ │ ├── gendoc.go
│ │ └── client.ts
│ ├── go.mod
│ └── go.sum
├── showpaths.go
├── typescriptclient.tmpl
├── gendoc.go
└── typescript.go
├── _example
├── todo
│ ├── frontend
│ │ ├── src
│ │ │ ├── vite-env.d.ts
│ │ │ ├── App.css
│ │ │ ├── main.tsx
│ │ │ ├── index.css
│ │ │ ├── tasks.ts
│ │ │ ├── App.tsx
│ │ │ └── client.ts
│ │ ├── bun.lockb
│ │ ├── tsconfig.json
│ │ ├── vite.config.ts
│ │ ├── biome.json
│ │ ├── .gitignore
│ │ ├── index.html
│ │ ├── tsconfig.node.json
│ │ ├── tsconfig.app.json
│ │ └── package.json
│ ├── tools.go
│ ├── README.md
│ ├── go.mod
│ ├── main.go
│ └── go.sum
├── simple-use
│ └── main.go
└── simple-registry
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── util.go
├── cmd
├── showpaths
│ └── main.go
├── gentypescript
│ └── main.go
└── tanukiup
│ └── main.go
├── sessions
├── sessions.go
└── gorilla
│ └── sessions.go
├── .gitignore
├── logger.go
├── LICENSE
├── accesslog.go
├── internal
└── requestid
│ └── requestid.go
├── go.mod
├── validator.go
├── error.go
├── handler.go
├── server.go
├── router.go
├── context.go
├── auth
└── oidc
│ └── oidc.go
├── go.sum
├── router_test.go
├── codec.go
├── tanukiup
└── tanukiup.go
└── README.md
/genclient/utils.go:
--------------------------------------------------------------------------------
1 | package genclient
2 |
--------------------------------------------------------------------------------
/genclient/typescript/generator.go:
--------------------------------------------------------------------------------
1 | package typescript
2 |
--------------------------------------------------------------------------------
/_example/todo/frontend/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
>(path: P, args: pathCallArgs<`POST ${P}`>) => Promise >(path: P, args: pathCallArgs<`GET ${P}`>) => Promise >(path: P, args: pathCallArgs<`POST ${P}`>) => await fetchByPath("POST", path, args)
102 | const get = async >(path: P, args: pathCallArgs<`GET ${P}`>) => await fetchByPath("GET", path, args)
103 |
104 | return {
105 | post,
106 | get,
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/cmd/tanukiup/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "log/slog"
7 | "os"
8 | "os/signal"
9 | "strings"
10 | "syscall"
11 |
12 | "github.com/mackee/tanukirpc/tanukiup"
13 | "github.com/urfave/cli/v2"
14 | )
15 |
16 | func main() {
17 | app := &cli.App{
18 | Name: "tanukiup",
19 | Usage: "tanukiup is a tool to run your server and watch your files",
20 | Flags: []cli.Flag{
21 | &cli.StringSliceFlag{
22 | Name: "ext",
23 | Usage: "file extensions to watch",
24 | },
25 | &cli.StringSliceFlag{
26 | Name: "dir",
27 | Usage: "directories to watch",
28 | },
29 | &cli.StringSliceFlag{
30 | Name: "ignore-dir",
31 | Usage: "directories to ignore",
32 | },
33 | &cli.StringFlag{
34 | Name: "build",
35 | Usage: "build command. {outpath} represents the output path.",
36 | DefaultText: "go build -o {outpath} ./",
37 | },
38 | &cli.StringFlag{
39 | Name: "exec",
40 | Usage: "exec command. {outpath} represents the output path.",
41 | DefaultText: "{outpath}",
42 | },
43 | &cli.StringFlag{
44 | Name: "addr",
45 | Usage: "port number to run the server. this use for the proxy mode.",
46 | },
47 | &cli.StringFlag{
48 | Name: "base-dir",
49 | Usage: "base directory to watch. if not specified, the current directory is used",
50 | },
51 | &cli.StringFlag{
52 | Name: "temp-dir",
53 | Usage: "temporary directory to store the built binary. if not specified, the system's temp directory is used",
54 | },
55 | &cli.StringFlag{
56 | Name: "handler-dir",
57 | Usage: "directory to watch for the handler files. if not specified, the base directory is used",
58 | },
59 | &cli.StringFlag{
60 | Name: "catchall-target",
61 | Usage: "target to catch all requests. if not specified, the server returns 404",
62 | },
63 | &cli.StringFlag{
64 | Name: "log-level",
65 | Usage: "log level (debug, info, warn, error)",
66 | },
67 | },
68 | Action: run,
69 | }
70 |
71 | if err := app.Run(os.Args); err != nil {
72 | panic(err)
73 | }
74 | }
75 |
76 | func run(cctx *cli.Context) error {
77 | opts := tanukiup.Options{}
78 | if exts := cctx.StringSlice("ext"); len(exts) > 0 {
79 | opts = append(opts, tanukiup.WithFileExts(exts))
80 | }
81 | if dirs := cctx.StringSlice("dir"); len(dirs) > 0 {
82 | opts = append(opts, tanukiup.WithDirs(dirs))
83 | }
84 | if ignoreDirs := cctx.StringSlice("ignore-dir"); len(ignoreDirs) > 0 {
85 | opts = append(opts, tanukiup.WithIgnoreDirs(ignoreDirs))
86 | }
87 | if port := cctx.String("addr"); port != "" {
88 | opts = append(opts, tanukiup.WithAddr(port))
89 | }
90 | if logLevel := cctx.String("log-level"); logLevel != "" {
91 | levelMap := map[string]slog.Level{
92 | "debug": slog.LevelDebug,
93 | "info": slog.LevelInfo,
94 | "warn": slog.LevelWarn,
95 | "error": slog.LevelError,
96 | }
97 | if lv, ok := levelMap[logLevel]; ok {
98 | opts = append(opts, tanukiup.WithLogLevel(lv))
99 | } else {
100 | return fmt.Errorf("unknown log level: %s", logLevel)
101 | }
102 | }
103 | if build := cctx.String("build"); build != "" {
104 | bc := strings.Fields(build)
105 | opts = append(opts, tanukiup.WithBuildCommand(bc))
106 | }
107 | if exec := cctx.String("exec"); exec != "" {
108 | ec := strings.Fields(exec)
109 | opts = append(opts, tanukiup.WithExecCommand(ec))
110 | }
111 | if basedir := cctx.String("base-dir"); basedir != "" {
112 | opts = append(opts, tanukiup.WithBaseDir(basedir))
113 | }
114 | if tempdir := cctx.String("temp-dir"); tempdir != "" {
115 | opts = append(opts, tanukiup.WithTempDir(tempdir))
116 | }
117 | if catchallTarget := cctx.String("catchall-target"); catchallTarget != "" {
118 | opts = append(opts, tanukiup.WithCatchAllTarget(catchallTarget))
119 | }
120 | if handlerDir := cctx.String("handler-dir"); handlerDir != "" {
121 | opts = append(opts, tanukiup.WithHandlerDir(handlerDir))
122 | }
123 |
124 | ctx, cancel := context.WithCancel(cctx.Context)
125 |
126 | sig := make(chan os.Signal, 1)
127 | signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
128 | go func() {
129 | <-sig
130 | cancel()
131 | }()
132 |
133 | if err := tanukiup.Run(ctx, opts...); err != nil {
134 | return fmt.Errorf("failed to run tanukiup: %w", err)
135 | }
136 | return nil
137 | }
138 |
--------------------------------------------------------------------------------
/_example/todo/frontend/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { FaPlusCircle, FaBan, FaEdit, FaCheck, FaTrash } from "react-icons/fa";
2 | import { type ReactNode, useState } from "react";
3 | import { fetchTasks, addTask, deleteTask, updateTask } from "./tasks";
4 | import "./App.css";
5 |
6 | function App() {
7 | return (
8 | <>
9 |
93 | {name}TODO App Demo
10 | Task #{taskId}
196 | Description
202 |