@gnosticdev/hono-actions 2.0.11 → 2.1.1

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/dist/actions.js DELETED
@@ -1,87 +0,0 @@
1
- import { zValidator } from '@hono/zod-validator';
2
- import { z } from 'astro/zod';
3
- import { Hono } from 'hono';
4
-
5
- // src/define-action.ts
6
-
7
- // src/error.ts
8
- var HonoActionError = class extends Error {
9
- code;
10
- issue;
11
- constructor({
12
- message,
13
- code,
14
- issue
15
- }) {
16
- super(message);
17
- this.name = "HonoActionError";
18
- this.code = code;
19
- this.issue = issue;
20
- }
21
- };
22
-
23
- // src/define-action.ts
24
- function defineHonoAction({ schema, handler }) {
25
- const app = new Hono();
26
- const route = app.post(
27
- "/",
28
- zValidator(
29
- "json",
30
- schema ?? z.any(),
31
- async (result, c) => {
32
- if (!result.success) {
33
- console.error(result.error.issues);
34
- const firstIssue = result.error.issues[0];
35
- return c.json(
36
- {
37
- data: null,
38
- error: new HonoActionError({
39
- message: firstIssue?.message || "Validation error",
40
- code: "INPUT_VALIDATION_ERROR",
41
- issue: firstIssue
42
- })
43
- },
44
- 400
45
- );
46
- }
47
- }
48
- ),
49
- async (c) => {
50
- try {
51
- const json = c.req.valid("json");
52
- const result = await handler(
53
- json,
54
- c
55
- );
56
- return c.json(
57
- {
58
- data: result,
59
- error: null
60
- },
61
- 200
62
- );
63
- } catch (error) {
64
- console.error(error);
65
- let errorMessage = "Internal server error";
66
- let errorCode = "INTERNAL_SERVER_ERROR";
67
- if (error instanceof HonoActionError) {
68
- errorMessage = error.message;
69
- errorCode = error.code;
70
- }
71
- return c.json(
72
- {
73
- data: null,
74
- error: {
75
- message: errorMessage,
76
- code: errorCode
77
- }
78
- },
79
- 500
80
- );
81
- }
82
- }
83
- );
84
- return route;
85
- }
86
-
87
- export { HonoActionError, defineHonoAction };
package/dist/index.d.ts DELETED
@@ -1,54 +0,0 @@
1
- import * as astro from 'astro';
2
- import { z } from 'astro/zod';
3
-
4
- declare const optionsSchema: z.ZodOptional<z.ZodObject<{
5
- /**
6
- * The base path for the API routes
7
- *
8
- * @default '/api'
9
- */
10
- basePath: z.ZodOptional<z.ZodString>;
11
- /**
12
- * The path to the actions file. If not provided, the integration will automatically discover the actions file by searching for one of the following patterns:
13
- * - `src/server/actions.ts`
14
- * - `src/hono/actions.ts`
15
- * - `src/hono/index.ts`
16
- * - `src/hono.ts`
17
- * - `src/hono-actions.ts`
18
- *
19
- * **NOTE** `src/actions.ts` is reserved for Astro Actions and will be ignored.
20
- *
21
- * @default 'src/server/actions.ts'
22
- */
23
- actionsPath: z.ZodOptional<z.ZodString>;
24
- }, "strip", z.ZodTypeAny, {
25
- basePath?: string | undefined;
26
- actionsPath?: string | undefined;
27
- }, {
28
- basePath?: string | undefined;
29
- actionsPath?: string | undefined;
30
- }>>;
31
- type IntegrationOptions = z.output<typeof optionsSchema>;
32
- /**
33
- * Astro integration for Hono Actions
34
- *
35
- * This integration automatically discovers action files in your project,
36
- * generates type-safe client code, and sets up API routes.
37
- *
38
- * Supprted Adapters:
39
- * - @astrojs/cloudflare
40
- * - @astrojs/node
41
- * - @astrojs/vercel
42
- * - @astrojs/netlify
43
- *
44
- *
45
- * @param options - Configuration options for the integration
46
- * @param options.basePath - Base path for API routes (default: '/api')
47
- * @param options.actionsPath - Custom path to actions file (optional, auto-discovered by default)
48
- */
49
- declare const _default: (options?: {
50
- basePath?: string | undefined;
51
- actionsPath?: string | undefined;
52
- } | undefined) => astro.AstroIntegration & {};
53
-
54
- export { type IntegrationOptions, _default as default };
package/dist/index.js DELETED
@@ -1,372 +0,0 @@
1
- import { defineIntegration, createResolver, addVirtualImports } from 'astro-integration-kit';
2
- import { z } from 'astro/zod';
3
- import fs from 'node:fs/promises';
4
- import path from 'node:path';
5
- import { glob } from 'tinyglobby';
6
-
7
- // src/integration.ts
8
-
9
- // src/integration-files.ts
10
- function generateRouter(opts) {
11
- const { basePath, relativeActionsPath, adapter } = opts;
12
- let exportedApp = "export default app";
13
- if (adapter === "@astrojs/netlify") {
14
- exportedApp = "export default handle(app)";
15
- }
16
- return `import type { HonoEnv, MergeActionKeyIntoPath } from '@gnosticdev/hono-actions/actions'
17
- import { Hono } from 'hono'
18
- import { cors } from 'hono/cors'
19
- import { showRoutes } from 'hono/dev'
20
- import { logger } from 'hono/logger'
21
- import { prettyJSON } from 'hono/pretty-json'
22
- import type { ExtractSchema, MergeSchemaPath } from 'hono/types'
23
- ${adapter === "@astrojs/netlify" ? "import { handle } from 'hono/netlify'" : ""}
24
-
25
- async function buildRouter(){
26
- type ActionsWithKeyedPaths = MergeActionKeyIntoPath<typeof honoActions>
27
- type ActionSchema = ExtractSchema<ActionsWithKeyedPaths[keyof ActionsWithKeyedPaths]>
28
- const { honoActions} = await import('${relativeActionsPath}')
29
- const app = new Hono<HonoEnv, MergeSchemaPath<ActionSchema, '${basePath}'>>().basePath('${basePath}')
30
-
31
- app.use('*', cors(), logger(), prettyJSON())
32
-
33
- for (const [routeName, action] of Object.entries(honoActions)) {
34
- app.route(\`/\${routeName}\`, action)
35
- }
36
-
37
- return app
38
- }
39
-
40
- export type HonoRouter = Awaited<ReturnType<typeof buildRouter>>
41
-
42
- const app = await buildRouter()
43
- console.log('------- Hono Routes -------')
44
- showRoutes(app)
45
- console.log('---------------------------')
46
- ${exportedApp}`;
47
- }
48
- var generateAstroHandler = (adapter) => {
49
- switch (adapter) {
50
- case "@astrojs/cloudflare":
51
- return `
52
- /// <reference types="./types.d.ts" />
53
- // Generated by Hono Actions Integration
54
- // adapter: ${adapter}
55
- import type { APIContext, APIRoute } from 'astro'
56
- import router from './router.js'
57
-
58
- const handler: APIRoute<APIContext> = async (ctx) => {
59
- return router.fetch(
60
- ctx.request,
61
- ctx.locals.runtime.env, // required for cloudflare adapter
62
- ctx.locals.runtime.ctx, // required for cloudflare adapter
63
- )
64
- }
65
-
66
- export { handler as ALL }
67
- `;
68
- case "@astrojs/node":
69
- case "@astrojs/vercel":
70
- return `
71
- /// <reference types="./types.d.ts" />
72
- // Generated by Hono Actions Integration
73
- // adapter: ${adapter}
74
- import type { APIContext, APIRoute } from 'astro'
75
- import router from './router.js'
76
-
77
- const handler: APIRoute<APIContext> = async (ctx) => {
78
- return router.fetch(
79
- ctx.request,
80
- )
81
- }
82
-
83
- export { handler as ALL }
84
- `;
85
- case "@astrojs/netlify":
86
- return `
87
- /// <reference types="./types.d.ts" />
88
- // Generated by Hono Actions Integration
89
- // adapter: ${adapter}
90
- import type { APIContext, APIRoute } from 'astro'
91
- import netlifyHandler from './router.js'
92
-
93
- const handler: APIRoute<APIContext> = async (ctx) => {
94
- return netlifyHandler(ctx.request, ctx)
95
- }
96
-
97
- export { handler as ALL }
98
- `;
99
- default:
100
- throw new Error(`Unsupported adapter: ${adapter}`);
101
- }
102
- };
103
- var generateHonoClient = (port) => `
104
- // Generated by Hono Actions Integration
105
- import type { HonoRouter } from './router.js'
106
- import { parseResponse, hc } from 'hono/client'
107
- import type { DetailedError, ClientRequestOptions } from 'hono/client'
108
-
109
- function getBaseUrl() {
110
- // client side can just use the origin
111
- if (typeof window !== 'undefined') {
112
- return window.location.origin
113
- }
114
-
115
- // dev server (dev server) needs to know the port
116
- if (import.meta.env.DEV) {
117
- return 'http://localhost:${port}'
118
- }
119
-
120
- // server side (production) needs full url
121
- if (import.meta.env.SITE) {
122
- return import.meta.env.SITE
123
- }
124
-
125
- return '/'
126
- }
127
-
128
- export { parseResponse }
129
- export type { DetailedError, ClientRequestOptions, HonoRouter }
130
- export const honoClient = createHonoClient<HonoRouter>(getBaseUrl())
131
- export function createHonoClient<T extends HonoRouter = HonoRouter>(basePath: string, fetchOptions?: ClientRequestOptions) {
132
- return hc<T>(basePath, fetchOptions)
133
- }
134
- `;
135
- var generateIntegrationTypes = (adapter) => {
136
- let actionTypes = `
137
- // Generated by Hono Actions Integration
138
- declare module '@gnosticdev/hono-actions/actions' {
139
- interface Bindings { [key: string]: unknown }
140
- interface Variables { [key: string]: unknown }
141
- interface HonoEnv { Bindings: Bindings, Variables: Variables }
142
- }
143
- export {}
144
- `;
145
- let clientTypes = `
146
- // Generated by Hono Actions Integration
147
- declare module '@gnosticdev/hono-actions/client' {
148
- /**
149
- * Default hono client using the base url from the environment
150
- * **Note** if running in production, the \`siteUrl\` option from the astro config will be used.
151
- * If customization is needed, use the \`createHonoClient\` function instead.
152
- */
153
- export const honoClient: typeof import('./client').honoClient
154
- /**
155
- * Helper function to parse the response from the Hono client
156
- */
157
- export const parseResponse: typeof import('./client').parseResponse
158
- /**
159
- * Create a new hono client with custom base url + fetch options
160
- */
161
- export const createHonoClient: typeof import('./client').createHonoClient
162
- export type DetailedError = import('./client').DetailedError
163
- export type ClientRequestOptions = import('./client').ClientRequestOptions
164
- /**
165
- * The hono actions routes. for use in the hono client
166
- */
167
- export type HonoRouter = import('./client').HonoRouter
168
- }
169
- `;
170
- switch (adapter) {
171
- // cloudflare uses Bindings and Variables passed in from the route handler
172
- case "@astrojs/cloudflare":
173
- actionTypes = `
174
- // Generated by Hono Actions Integration
175
- // keeping separate from the main types.d.ts to avoid clobbering package exports
176
- declare module '@gnosticdev/hono-actions/actions' {
177
- interface Bindings extends Env { ASTRO_LOCALS: App.Locals }
178
- interface Variables { [key: string]: unknown }
179
- interface HonoEnv { Bindings: Bindings, Variables: Variables }
180
- }
181
- export {}
182
- `;
183
- clientTypes += `
184
- type Runtime = import('@astrojs/cloudflare').Runtime<Env>
185
-
186
- declare namespace App {
187
- interface Locals extends Runtime {}
188
- }
189
- `;
190
- break;
191
- }
192
- return { actionTypes, clientTypes };
193
- };
194
-
195
- // src/lib/utils.ts
196
- var reservedRoutes = ["_astro", "_actions", "_server_islands"];
197
- var SUPPORTED_ADAPTERS = ["@astrojs/cloudflare", "@astrojs/node", "@astrojs/netlify", "@astrojs/vercel"];
198
- function isSupportedAdapter(adapter) {
199
- return SUPPORTED_ADAPTERS.includes(adapter);
200
- }
201
-
202
- // src/integration.ts
203
- var optionsSchema = z.object({
204
- /**
205
- * The base path for the API routes
206
- *
207
- * @default '/api'
208
- */
209
- basePath: z.string().optional(),
210
- /**
211
- * The path to the actions file. If not provided, the integration will automatically discover the actions file by searching for one of the following patterns:
212
- * - `src/server/actions.ts`
213
- * - `src/hono/actions.ts`
214
- * - `src/hono/index.ts`
215
- * - `src/hono.ts`
216
- * - `src/hono-actions.ts`
217
- *
218
- * **NOTE** `src/actions.ts` is reserved for Astro Actions and will be ignored.
219
- *
220
- * @default 'src/server/actions.ts'
221
- */
222
- actionsPath: z.string().optional()
223
- }).optional();
224
- var VIRTUAL_MODULE_ID_CLIENT = "@gnosticdev/hono-actions/client";
225
- var VIRTUAL_MODULE_ID_ROUTER = "virtual:hono-actions/router";
226
- var ACTION_PATTERNS = [
227
- "src/server/actions.ts",
228
- "src/hono/actions.ts",
229
- "src/hono/index.ts",
230
- "src/hono.ts",
231
- "src/hono-actions.ts"
232
- ];
233
- var integration_default = defineIntegration({
234
- name: "@gnosticdev/hono-actions",
235
- optionsSchema,
236
- setup: ({ options = {}, name }) => {
237
- const basePath = options.basePath ?? "/api";
238
- if (reservedRoutes.includes(basePath)) {
239
- throw new Error(
240
- `Base path ${basePath} is reserved by Astro; pick another (e.g. /api2).`
241
- );
242
- }
243
- const { resolve } = createResolver(import.meta.url);
244
- const IS_DEBUG = process.env.__DEBUG__ === "true";
245
- return {
246
- name,
247
- hooks: {
248
- "astro:config:setup": async (params) => {
249
- const { logger, injectRoute, createCodegenDir, config } = params;
250
- const root = config.root.pathname;
251
- const absPatterns = ACTION_PATTERNS.map(
252
- (p) => path.join(root, p)
253
- );
254
- const files = await glob(absPatterns, {
255
- expandDirectories: false,
256
- absolute: true
257
- });
258
- if (IS_DEBUG) {
259
- logger.info(`DEBUG: Found actions: ${files.join("\n")}`);
260
- }
261
- const actionsPath = options.actionsPath ?? files[0];
262
- if (!actionsPath || actionsPath.includes("node_modules")) {
263
- logger.warn(
264
- `No actions found. Create one of:
265
- ${ACTION_PATTERNS.map((p) => ` - ${p}`).join("\n")}`
266
- );
267
- return;
268
- }
269
- const resolvedActionsPath = resolve(actionsPath);
270
- params.addWatchFile(resolvedActionsPath);
271
- logger.info(
272
- `Found actions: ${path.relative(root, resolvedActionsPath)}`
273
- );
274
- const codeGenDir = createCodegenDir();
275
- const routerPathAbs = path.join(
276
- codeGenDir.pathname,
277
- "router.ts"
278
- );
279
- const relFromGenToActions = path.relative(codeGenDir.pathname, resolvedActionsPath).split(path.sep).join("/");
280
- const adapter = params.config.adapter?.name;
281
- if (!adapter) {
282
- logger.error(
283
- `No Astro adapter found. Add one of:
284
- - ${SUPPORTED_ADAPTERS.join("\n - ")} to your astro.config.mjs`
285
- );
286
- return;
287
- }
288
- if (!isSupportedAdapter(adapter)) {
289
- logger.error(
290
- `Unsupported adapter: ${adapter}. Only ${SUPPORTED_ADAPTERS.join("\n - ")} are supported`
291
- );
292
- return;
293
- }
294
- const routerContent = generateRouter({
295
- basePath,
296
- relativeActionsPath: relFromGenToActions,
297
- adapter
298
- });
299
- await fs.writeFile(routerPathAbs, routerContent, "utf-8");
300
- const astroHandlerPathAbs = path.join(
301
- codeGenDir.pathname,
302
- "api.ts"
303
- );
304
- const astroHandlerContent = generateAstroHandler(adapter);
305
- await fs.writeFile(
306
- astroHandlerPathAbs,
307
- astroHandlerContent,
308
- "utf-8"
309
- );
310
- const clientPathAbs = path.join(
311
- codeGenDir.pathname,
312
- "client.ts"
313
- );
314
- if (!config.site) {
315
- logger.warn(
316
- "No site url found in astro config, add one if you want to use the hono client with SSR"
317
- );
318
- }
319
- const clientContent = generateHonoClient(config.server.port);
320
- await fs.writeFile(clientPathAbs, clientContent, "utf-8");
321
- addVirtualImports(params, {
322
- name,
323
- imports: {
324
- [VIRTUAL_MODULE_ID_CLIENT]: `export * from '${clientPathAbs}';`,
325
- [VIRTUAL_MODULE_ID_ROUTER]: `export * from '${routerPathAbs}';`
326
- }
327
- });
328
- logger.info("\u2705 Hono Actions virtual imports added");
329
- injectRoute({
330
- pattern: `${basePath}/[...slug]`,
331
- entrypoint: astroHandlerPathAbs,
332
- prerender: false
333
- });
334
- logger.info(
335
- `\u2705 Hono Actions route mounted at ${basePath}/[...slug]`
336
- );
337
- },
338
- "astro:config:done": async ({
339
- injectTypes,
340
- config,
341
- logger
342
- }) => {
343
- const adapter = config.adapter?.name;
344
- if (!adapter) {
345
- logger.warn("No adapter found...");
346
- return;
347
- }
348
- if (!isSupportedAdapter(adapter)) {
349
- logger.warn(
350
- `Unsupported adapter: ${adapter}. Only ${SUPPORTED_ADAPTERS.join("\n - ")} are supported`
351
- );
352
- return;
353
- }
354
- const { actionTypes, clientTypes } = generateIntegrationTypes(adapter);
355
- injectTypes({
356
- filename: "actions.d.ts",
357
- content: actionTypes
358
- });
359
- injectTypes({
360
- filename: "types.d.ts",
361
- content: clientTypes
362
- });
363
- }
364
- }
365
- };
366
- }
367
- });
368
-
369
- // src/index.ts
370
- var src_default = integration_default;
371
-
372
- export { src_default as default };