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