@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/README.md +3 -1
- package/dist/actions.d.mts +380 -0
- package/dist/actions.mjs +132 -0
- package/dist/index.d.mts +32 -0
- package/dist/index.mjs +418 -0
- package/package.json +17 -16
- package/dist/actions.d.ts +0 -160
- package/dist/actions.js +0 -87
- package/dist/index.d.ts +0 -54
- package/dist/index.js +0 -372
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import z from "astro/zod";
|
|
2
|
+
import * as _$astro from "astro";
|
|
3
|
+
|
|
4
|
+
//#region src/integration.d.ts
|
|
5
|
+
declare const optionsSchema: z.ZodOptional<z.ZodObject<{
|
|
6
|
+
basePath: z.ZodOptional<z.ZodString>;
|
|
7
|
+
actionsPath: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, z.core.$strip>>;
|
|
9
|
+
type IntegrationOptions = z.output<typeof optionsSchema>;
|
|
10
|
+
/**
|
|
11
|
+
* Astro integration for Hono Actions
|
|
12
|
+
*
|
|
13
|
+
* This integration automatically discovers action files in your project,
|
|
14
|
+
* generates type-safe client code, and sets up API routes.
|
|
15
|
+
*
|
|
16
|
+
* Supprted Adapters:
|
|
17
|
+
* - @astrojs/cloudflare
|
|
18
|
+
* - @astrojs/node
|
|
19
|
+
* - @astrojs/vercel
|
|
20
|
+
* - @astrojs/netlify
|
|
21
|
+
*
|
|
22
|
+
*
|
|
23
|
+
* @param options - Configuration options for the integration
|
|
24
|
+
* @param options.basePath - Base path for API routes (default: '/api')
|
|
25
|
+
* @param options.actionsPath - Custom path to actions file (optional, auto-discovered by default)
|
|
26
|
+
*/
|
|
27
|
+
declare const _default: (options?: {
|
|
28
|
+
basePath?: string | undefined;
|
|
29
|
+
actionsPath?: string | undefined;
|
|
30
|
+
} | undefined) => _$astro.AstroIntegration & {};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { type IntegrationOptions, _default as default };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import z from "astro/zod";
|
|
3
|
+
import { addVirtualImports, createResolver, defineIntegration } from "astro-integration-kit";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { glob } from "tinyglobby";
|
|
7
|
+
|
|
8
|
+
//#region src/integration-files.ts
|
|
9
|
+
/**
|
|
10
|
+
* Generate router using the buildRouter pattern for better type inference
|
|
11
|
+
* @param opts - The options for generating the router
|
|
12
|
+
* @param opts.basePath - The base path for the router
|
|
13
|
+
* @param opts.relativeActionsPath - The relative path to the actions file
|
|
14
|
+
* @param opts.adapter - The adapter to use for generating the router
|
|
15
|
+
* @returns The generated router code
|
|
16
|
+
*
|
|
17
|
+
* **Supported Adapters:**
|
|
18
|
+
* - `@astrojs/cloudflare`
|
|
19
|
+
* - `@astrojs/node`
|
|
20
|
+
* - `@astrojs/vercel`
|
|
21
|
+
* - `@astrojs/netlify`
|
|
22
|
+
*/
|
|
23
|
+
function generateRouter(opts) {
|
|
24
|
+
const { basePath, relativeActionsPath, adapter } = opts;
|
|
25
|
+
let exportedApp = "export default app";
|
|
26
|
+
if (adapter === "@astrojs/netlify") exportedApp = "export default handle(app)";
|
|
27
|
+
return `import type { HonoEnv, MergeActionKeyIntoPath } from '@gnosticdev/hono-actions/actions'
|
|
28
|
+
import { Hono } from 'hono'
|
|
29
|
+
import { cors } from 'hono/cors'
|
|
30
|
+
import { showRoutes } from 'hono/dev'
|
|
31
|
+
import { logger } from 'hono/logger'
|
|
32
|
+
import { prettyJSON } from 'hono/pretty-json'
|
|
33
|
+
import type { ExtractSchema, MergeSchemaPath } from 'hono/types'
|
|
34
|
+
${adapter === "@astrojs/netlify" ? "import { handle } from 'hono/netlify'" : ""}
|
|
35
|
+
|
|
36
|
+
async function buildRouter(){
|
|
37
|
+
type ActionsWithKeyedPaths = MergeActionKeyIntoPath<typeof honoActions>
|
|
38
|
+
type ActionSchema = ExtractSchema<ActionsWithKeyedPaths[keyof ActionsWithKeyedPaths]>
|
|
39
|
+
const { honoActions} = await import('${relativeActionsPath}')
|
|
40
|
+
const app = new Hono<HonoEnv, MergeSchemaPath<ActionSchema, '${basePath}'>>().basePath('${basePath}')
|
|
41
|
+
|
|
42
|
+
app.use('*', cors(), logger(), prettyJSON())
|
|
43
|
+
|
|
44
|
+
for (const [routeName, action] of Object.entries(honoActions)) {
|
|
45
|
+
app.route(\`/\${routeName}\`, action)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return app
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type HonoRouter = Awaited<ReturnType<typeof buildRouter>>
|
|
52
|
+
|
|
53
|
+
const app = await buildRouter()
|
|
54
|
+
console.log('------- Hono Routes -------')
|
|
55
|
+
showRoutes(app)
|
|
56
|
+
console.log('---------------------------')
|
|
57
|
+
${exportedApp}`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Injects the Hono router into the Astro API route handler at `src/pages/api/[...slug].ts`
|
|
61
|
+
*
|
|
62
|
+
* @param adapter - The adapter in use from the astro config
|
|
63
|
+
*
|
|
64
|
+
* For use with `@astrojs/cloudflare` adapter only (for now).a
|
|
65
|
+
*/
|
|
66
|
+
const generateAstroHandler = (adapter, astroMajorVersion = 5) => {
|
|
67
|
+
switch (adapter) {
|
|
68
|
+
case "@astrojs/cloudflare":
|
|
69
|
+
if (astroMajorVersion >= 6) return `
|
|
70
|
+
/// <reference types="./types.d.ts" />
|
|
71
|
+
// Generated by Hono Actions Integration
|
|
72
|
+
// adapter: ${adapter}
|
|
73
|
+
import { env } from 'cloudflare:workers'
|
|
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
|
+
...env,
|
|
82
|
+
ASTRO_LOCALS: ctx.locals,
|
|
83
|
+
},
|
|
84
|
+
ctx.locals.cfContext,
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export { handler as ALL }
|
|
89
|
+
`;
|
|
90
|
+
return `
|
|
91
|
+
/// <reference types="./types.d.ts" />
|
|
92
|
+
// Generated by Hono Actions Integration
|
|
93
|
+
// adapter: ${adapter}
|
|
94
|
+
import type { APIContext, APIRoute } from 'astro'
|
|
95
|
+
import router from './router.js'
|
|
96
|
+
|
|
97
|
+
const handler: APIRoute<APIContext> = async (ctx) => {
|
|
98
|
+
return router.fetch(
|
|
99
|
+
ctx.request,
|
|
100
|
+
{
|
|
101
|
+
...ctx.locals.runtime.env,
|
|
102
|
+
ASTRO_LOCALS: ctx.locals,
|
|
103
|
+
},
|
|
104
|
+
ctx.locals.runtime.ctx, // required for cloudflare adapter
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export { handler as ALL }
|
|
109
|
+
`;
|
|
110
|
+
case "@astrojs/node":
|
|
111
|
+
case "@astrojs/vercel": return `
|
|
112
|
+
/// <reference types="./types.d.ts" />
|
|
113
|
+
// Generated by Hono Actions Integration
|
|
114
|
+
// adapter: ${adapter}
|
|
115
|
+
import type { APIContext, APIRoute } from 'astro'
|
|
116
|
+
import router from './router.js'
|
|
117
|
+
|
|
118
|
+
const handler: APIRoute<APIContext> = async (ctx) => {
|
|
119
|
+
return router.fetch(
|
|
120
|
+
ctx.request,
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export { handler as ALL }
|
|
125
|
+
`;
|
|
126
|
+
case "@astrojs/netlify": return `
|
|
127
|
+
/// <reference types="./types.d.ts" />
|
|
128
|
+
// Generated by Hono Actions Integration
|
|
129
|
+
// adapter: ${adapter}
|
|
130
|
+
import type { APIContext, APIRoute } from 'astro'
|
|
131
|
+
import netlifyHandler from './router.js'
|
|
132
|
+
|
|
133
|
+
const handler: APIRoute<APIContext> = async (ctx) => {
|
|
134
|
+
return netlifyHandler(ctx.request, ctx)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export { handler as ALL }
|
|
138
|
+
`;
|
|
139
|
+
default: throw new Error(`Unsupported adapter: ${adapter}`);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Generate Hono client code
|
|
144
|
+
*
|
|
145
|
+
* @param port - The port number for the dev server
|
|
146
|
+
*/
|
|
147
|
+
const generateHonoClient = (port) => `
|
|
148
|
+
// Generated by Hono Actions Integration
|
|
149
|
+
import type { HonoRouter } from './router.js'
|
|
150
|
+
import { parseResponse, hc } from 'hono/client'
|
|
151
|
+
import type { DetailedError, ClientRequestOptions } from 'hono/client'
|
|
152
|
+
|
|
153
|
+
function getBaseUrl() {
|
|
154
|
+
// client side can just use the origin
|
|
155
|
+
if (typeof window !== 'undefined') {
|
|
156
|
+
return window.location.origin
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// dev server (dev server) needs to know the port
|
|
160
|
+
if (import.meta.env.DEV) {
|
|
161
|
+
return 'http://localhost:${port}'
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// server side (production) needs full url
|
|
165
|
+
if (import.meta.env.SITE) {
|
|
166
|
+
return import.meta.env.SITE
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return '/'
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export { parseResponse }
|
|
173
|
+
export type { DetailedError, ClientRequestOptions, HonoRouter }
|
|
174
|
+
export const honoClient = createHonoClient<HonoRouter>(getBaseUrl())
|
|
175
|
+
export function createHonoClient<T extends HonoRouter = HonoRouter>(basePath: string, fetchOptions?: ClientRequestOptions) {
|
|
176
|
+
return hc<T>(basePath, fetchOptions)
|
|
177
|
+
}
|
|
178
|
+
`;
|
|
179
|
+
/**
|
|
180
|
+
* Emits `actions.d.ts` / client module declarations for the active adapter.
|
|
181
|
+
*
|
|
182
|
+
* For `@astrojs/cloudflare` on Astro 5 and below, appends `App.Locals` + `Runtime` so `ASTRO_LOCALS` matches
|
|
183
|
+
* `ctx.locals`. From Astro 6 onward the Cloudflare adapter already declares `App.Locals`, so that block is omitted.
|
|
184
|
+
*/
|
|
185
|
+
const generateIntegrationTypes = (adapter, astroMajorVersion = 5) => {
|
|
186
|
+
let actionTypes = `
|
|
187
|
+
// Generated by Hono Actions Integration
|
|
188
|
+
declare module '@gnosticdev/hono-actions/actions' {
|
|
189
|
+
interface Bindings { [key: string]: unknown }
|
|
190
|
+
interface Variables { [key: string]: unknown }
|
|
191
|
+
interface HonoEnv { Bindings: Bindings, Variables: Variables }
|
|
192
|
+
}
|
|
193
|
+
export {}
|
|
194
|
+
`;
|
|
195
|
+
let clientTypes = `
|
|
196
|
+
// Generated by Hono Actions Integration
|
|
197
|
+
declare module '@gnosticdev/hono-actions/client' {
|
|
198
|
+
/**
|
|
199
|
+
* Default hono client using the base url from the environment
|
|
200
|
+
* **Note** if running in production, the \`siteUrl\` option from the astro config will be used.
|
|
201
|
+
* If customization is needed, use the \`createHonoClient\` function instead.
|
|
202
|
+
*/
|
|
203
|
+
export const honoClient: typeof import('./client').honoClient
|
|
204
|
+
/**
|
|
205
|
+
* Helper function to parse the response from the Hono client
|
|
206
|
+
*/
|
|
207
|
+
export const parseResponse: typeof import('./client').parseResponse
|
|
208
|
+
/**
|
|
209
|
+
* Create a new hono client with custom base url + fetch options
|
|
210
|
+
*/
|
|
211
|
+
export const createHonoClient: typeof import('./client').createHonoClient
|
|
212
|
+
export type DetailedError = import('./client').DetailedError
|
|
213
|
+
export type ClientRequestOptions = import('./client').ClientRequestOptions
|
|
214
|
+
/**
|
|
215
|
+
* The hono actions routes. for use in the hono client
|
|
216
|
+
*/
|
|
217
|
+
export type HonoRouter = import('./client').HonoRouter
|
|
218
|
+
}
|
|
219
|
+
`;
|
|
220
|
+
switch (adapter) {
|
|
221
|
+
case "@astrojs/cloudflare":
|
|
222
|
+
actionTypes = `
|
|
223
|
+
// Generated by Hono Actions Integration
|
|
224
|
+
// keeping separate from the main types.d.ts to avoid clobbering package exports
|
|
225
|
+
declare module '@gnosticdev/hono-actions/actions' {
|
|
226
|
+
interface Bindings extends Env { ASTRO_LOCALS: App.Locals }
|
|
227
|
+
interface Variables { [key: string]: unknown }
|
|
228
|
+
interface HonoEnv { Bindings: Bindings, Variables: Variables }
|
|
229
|
+
}
|
|
230
|
+
export {}
|
|
231
|
+
`;
|
|
232
|
+
if (astroMajorVersion < 6) clientTypes += `
|
|
233
|
+
type Runtime = import('@astrojs/cloudflare').Runtime<Env>
|
|
234
|
+
|
|
235
|
+
declare namespace App {
|
|
236
|
+
interface Locals extends Runtime {}
|
|
237
|
+
}
|
|
238
|
+
`;
|
|
239
|
+
break;
|
|
240
|
+
default: break;
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
actionTypes,
|
|
244
|
+
clientTypes
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region src/lib/utils.ts
|
|
250
|
+
/**
|
|
251
|
+
* Reserved routes that are not allowed to be used for actions.
|
|
252
|
+
* @see https://docs.astro.build/en/guides/routing/#reserved-routes
|
|
253
|
+
*/
|
|
254
|
+
const reservedRoutes = [
|
|
255
|
+
"_astro",
|
|
256
|
+
"_actions",
|
|
257
|
+
"_server_islands"
|
|
258
|
+
];
|
|
259
|
+
const SUPPORTED_ADAPTERS = [
|
|
260
|
+
"@astrojs/cloudflare",
|
|
261
|
+
"@astrojs/node",
|
|
262
|
+
"@astrojs/netlify",
|
|
263
|
+
"@astrojs/vercel"
|
|
264
|
+
];
|
|
265
|
+
function isSupportedAdapter(adapter) {
|
|
266
|
+
return SUPPORTED_ADAPTERS.includes(adapter);
|
|
267
|
+
}
|
|
268
|
+
function parseAstroMajorVersion(version) {
|
|
269
|
+
const majorVersion = Number.parseInt(version, 10);
|
|
270
|
+
if (Number.isNaN(majorVersion)) if (process.env.PACKAGE_VERSION) return Number.parseInt(process.env.PACKAGE_VERSION, 10);
|
|
271
|
+
else throw new Error(`Invalid Astro version: ${version}`);
|
|
272
|
+
return majorVersion;
|
|
273
|
+
}
|
|
274
|
+
function getInstalledAstroVersion() {
|
|
275
|
+
const astroPackage = createRequire(import.meta.url)("astro/package.json");
|
|
276
|
+
if (!astroPackage.version) throw new Error("Could not determine installed Astro version");
|
|
277
|
+
return astroPackage.version;
|
|
278
|
+
}
|
|
279
|
+
function getInstalledAstroMajorVersion() {
|
|
280
|
+
return parseAstroMajorVersion(getInstalledAstroVersion());
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/integration.ts
|
|
285
|
+
const optionsSchema = z.object({
|
|
286
|
+
basePath: z.string().optional(),
|
|
287
|
+
actionsPath: z.string().optional()
|
|
288
|
+
}).optional();
|
|
289
|
+
const VIRTUAL_MODULE_ID_CLIENT = "@gnosticdev/hono-actions/client";
|
|
290
|
+
const VIRTUAL_MODULE_ID_ROUTER = "virtual:hono-actions/router";
|
|
291
|
+
const ACTION_PATTERNS = [
|
|
292
|
+
"src/server/actions.ts",
|
|
293
|
+
"src/hono/actions.ts",
|
|
294
|
+
"src/hono/index.ts",
|
|
295
|
+
"src/hono.ts",
|
|
296
|
+
"src/hono-actions.ts"
|
|
297
|
+
];
|
|
298
|
+
/**
|
|
299
|
+
* Astro integration for Hono Actions
|
|
300
|
+
*
|
|
301
|
+
* This integration automatically discovers action files in your project,
|
|
302
|
+
* generates type-safe client code, and sets up API routes.
|
|
303
|
+
*
|
|
304
|
+
* Supprted Adapters:
|
|
305
|
+
* - @astrojs/cloudflare
|
|
306
|
+
* - @astrojs/node
|
|
307
|
+
* - @astrojs/vercel
|
|
308
|
+
* - @astrojs/netlify
|
|
309
|
+
*
|
|
310
|
+
*
|
|
311
|
+
* @param options - Configuration options for the integration
|
|
312
|
+
* @param options.basePath - Base path for API routes (default: '/api')
|
|
313
|
+
* @param options.actionsPath - Custom path to actions file (optional, auto-discovered by default)
|
|
314
|
+
*/
|
|
315
|
+
var integration_default = defineIntegration({
|
|
316
|
+
name: "@gnosticdev/hono-actions",
|
|
317
|
+
optionsSchema,
|
|
318
|
+
setup: ({ options = {}, name }) => {
|
|
319
|
+
const basePath = options.basePath ?? "/api";
|
|
320
|
+
if (reservedRoutes.includes(basePath)) throw new Error(`Base path ${basePath} is reserved by Astro; pick another (e.g. /api2).`);
|
|
321
|
+
const { resolve } = createResolver(import.meta.url);
|
|
322
|
+
const IS_DEBUG = process.env.__DEBUG__ === "true";
|
|
323
|
+
const astroMajorVersion = getInstalledAstroMajorVersion();
|
|
324
|
+
return {
|
|
325
|
+
name,
|
|
326
|
+
hooks: {
|
|
327
|
+
"astro:config:setup": async (params) => {
|
|
328
|
+
const { logger, injectRoute, createCodegenDir, config } = params;
|
|
329
|
+
logger.info(`using astro major version: ${astroMajorVersion}`);
|
|
330
|
+
const root = config.root.pathname;
|
|
331
|
+
const files = await glob(ACTION_PATTERNS.map((p) => path.join(root, p)), {
|
|
332
|
+
expandDirectories: false,
|
|
333
|
+
absolute: true
|
|
334
|
+
});
|
|
335
|
+
if (IS_DEBUG) {
|
|
336
|
+
logger.info(`DEBUG: Detected Astro major version: ${astroMajorVersion}`);
|
|
337
|
+
logger.info(`DEBUG: Found actions: ${files.join("\n")}`);
|
|
338
|
+
}
|
|
339
|
+
const actionsPath = options.actionsPath ?? files[0];
|
|
340
|
+
if (!actionsPath || actionsPath.includes("node_modules")) {
|
|
341
|
+
logger.warn(`No actions found. Create one of:\n${ACTION_PATTERNS.map((p) => ` - ${p}`).join("\n")}`);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const resolvedActionsPath = resolve(actionsPath);
|
|
345
|
+
params.addWatchFile(resolvedActionsPath);
|
|
346
|
+
logger.info(`Found actions: ${path.relative(root, resolvedActionsPath)}`);
|
|
347
|
+
const codeGenDir = createCodegenDir();
|
|
348
|
+
const routerPathAbs = path.join(codeGenDir.pathname, "router.ts");
|
|
349
|
+
const relFromGenToActions = path.relative(codeGenDir.pathname, resolvedActionsPath).split(path.sep).join("/");
|
|
350
|
+
const adapter = params.config.adapter?.name;
|
|
351
|
+
if (!adapter) {
|
|
352
|
+
logger.error(`No Astro adapter found. Add one of:
|
|
353
|
+
- ${SUPPORTED_ADAPTERS.join("\n - ")} to your astro.config.mjs`);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
if (!isSupportedAdapter(adapter)) {
|
|
357
|
+
logger.error(`Unsupported adapter: ${adapter}. Only ${SUPPORTED_ADAPTERS.join("\n - ")} are supported`);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
const routerContent = generateRouter({
|
|
361
|
+
basePath,
|
|
362
|
+
relativeActionsPath: relFromGenToActions,
|
|
363
|
+
adapter
|
|
364
|
+
});
|
|
365
|
+
await fs.writeFile(routerPathAbs, routerContent, "utf-8");
|
|
366
|
+
const astroHandlerPathAbs = path.join(codeGenDir.pathname, "api.ts");
|
|
367
|
+
const astroHandlerContent = generateAstroHandler(adapter, astroMajorVersion);
|
|
368
|
+
await fs.writeFile(astroHandlerPathAbs, astroHandlerContent, "utf-8");
|
|
369
|
+
const clientPathAbs = path.join(codeGenDir.pathname, "client.ts");
|
|
370
|
+
if (!config.site) logger.warn("No site url found in astro config, add one if you want to use the hono client with SSR");
|
|
371
|
+
const clientContent = generateHonoClient(config.server.port);
|
|
372
|
+
await fs.writeFile(clientPathAbs, clientContent, "utf-8");
|
|
373
|
+
addVirtualImports(params, {
|
|
374
|
+
name,
|
|
375
|
+
imports: {
|
|
376
|
+
[VIRTUAL_MODULE_ID_CLIENT]: `export * from '${clientPathAbs}';`,
|
|
377
|
+
[VIRTUAL_MODULE_ID_ROUTER]: `export * from '${routerPathAbs}';`
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
logger.info("✅ Hono Actions virtual imports added");
|
|
381
|
+
injectRoute({
|
|
382
|
+
pattern: `${basePath}/[...slug]`,
|
|
383
|
+
entrypoint: astroHandlerPathAbs,
|
|
384
|
+
prerender: false
|
|
385
|
+
});
|
|
386
|
+
logger.info(`✅ Hono Actions route mounted at ${basePath}/[...slug]`);
|
|
387
|
+
},
|
|
388
|
+
"astro:config:done": async ({ injectTypes, config, logger }) => {
|
|
389
|
+
const adapter = config.adapter?.name;
|
|
390
|
+
if (!adapter) {
|
|
391
|
+
logger.warn("No adapter found...");
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
if (!isSupportedAdapter(adapter)) {
|
|
395
|
+
logger.warn(`Unsupported adapter: ${adapter}. Only ${SUPPORTED_ADAPTERS.join("\n - ")} are supported`);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const { actionTypes, clientTypes } = generateIntegrationTypes(adapter, astroMajorVersion);
|
|
399
|
+
injectTypes({
|
|
400
|
+
filename: "actions.d.ts",
|
|
401
|
+
content: actionTypes
|
|
402
|
+
});
|
|
403
|
+
injectTypes({
|
|
404
|
+
filename: "types.d.ts",
|
|
405
|
+
content: clientTypes
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
//#endregion
|
|
414
|
+
//#region src/index.ts
|
|
415
|
+
var src_default = integration_default;
|
|
416
|
+
|
|
417
|
+
//#endregion
|
|
418
|
+
export { src_default as default };
|
package/package.json
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@hono/standard-validator": "^0.2.0",
|
|
8
|
-
"@hono/zod-validator": "^0.
|
|
9
|
-
"astro-integration-kit": "^0.
|
|
8
|
+
"@hono/zod-validator": "^0.7.6",
|
|
9
|
+
"astro-integration-kit": "^0.20.0",
|
|
10
10
|
"tinyglobby": "^0.2.15"
|
|
11
11
|
},
|
|
12
12
|
"description": "Define server actions with built-in validation, error handling, and a pre-built hono client for calling the routes.",
|
|
@@ -16,19 +16,15 @@
|
|
|
16
16
|
"@astrojs/node": "catalog:",
|
|
17
17
|
"@astrojs/vercel": "catalog:",
|
|
18
18
|
"@biomejs/biome": "catalog:",
|
|
19
|
+
"@standard-schema/spec": "^1.1.0",
|
|
19
20
|
"astro": "catalog:",
|
|
20
|
-
"
|
|
21
|
+
"tsdown": "^0.21.7",
|
|
21
22
|
"typescript": "catalog:"
|
|
22
23
|
},
|
|
23
24
|
"exports": {
|
|
24
|
-
".":
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
"./*": {
|
|
29
|
-
"types": "./dist/*.d.ts",
|
|
30
|
-
"default": "./dist/*.js"
|
|
31
|
-
}
|
|
25
|
+
".": "./dist/index.mjs",
|
|
26
|
+
"./actions": "./dist/actions.mjs",
|
|
27
|
+
"./package.json": "./package.json"
|
|
32
28
|
},
|
|
33
29
|
"files": [
|
|
34
30
|
"dist"
|
|
@@ -45,21 +41,26 @@
|
|
|
45
41
|
"cloudflare"
|
|
46
42
|
],
|
|
47
43
|
"license": "MIT",
|
|
48
|
-
"main": "./dist/index.js",
|
|
49
44
|
"name": "@gnosticdev/hono-actions",
|
|
50
45
|
"peerDependencies": {
|
|
51
|
-
"astro": "^5.13.0",
|
|
46
|
+
"astro": "^5.13.0 || ^6.0.0",
|
|
52
47
|
"hono": "^4.10.6"
|
|
53
48
|
},
|
|
49
|
+
"optionalDependencies": {
|
|
50
|
+
"zod": "^4.3.6"
|
|
51
|
+
},
|
|
54
52
|
"publishConfig": {
|
|
55
53
|
"access": "public"
|
|
56
54
|
},
|
|
57
55
|
"scripts": {
|
|
58
|
-
"build": "
|
|
59
|
-
"dev": "
|
|
56
|
+
"build": "tsdown",
|
|
57
|
+
"dev": "tsdown --watch",
|
|
60
58
|
"typecheck": "tsc --noEmit"
|
|
61
59
|
},
|
|
62
60
|
"type": "module",
|
|
63
61
|
"types": "./dist/index.d.ts",
|
|
64
|
-
"version": "2.
|
|
62
|
+
"version": "2.1.1",
|
|
63
|
+
"inlinedDependencies": {
|
|
64
|
+
"@standard-schema/spec": "1.1.0"
|
|
65
|
+
}
|
|
65
66
|
}
|
package/dist/actions.d.ts
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import * as hono_hono_base from 'hono/hono-base';
|
|
2
|
-
import * as hono_utils_types from 'hono/utils/types';
|
|
3
|
-
import { z } from 'astro/zod';
|
|
4
|
-
import { Hono, Context } from 'hono';
|
|
5
|
-
import { MergeSchemaPath } from 'hono/types';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Standard error codes for actions
|
|
9
|
-
*/
|
|
10
|
-
type ActionErrorCode = 'INPUT_VALIDATION_ERROR' | 'EXTERNAL_API_ERROR' | 'INTERNAL_SERVER_ERROR' | 'UNKNOWN_ERROR' | 'LOCATION_NOT_FOUND' | 'SESSION_NOT_FOUND' | (string & {});
|
|
11
|
-
declare class HonoActionError<TMessage extends string, TCode extends ActionErrorCode, TIssue = any> extends Error {
|
|
12
|
-
code: TCode;
|
|
13
|
-
issue?: TIssue;
|
|
14
|
-
constructor({ message, code, issue, }: {
|
|
15
|
-
message: TMessage;
|
|
16
|
-
code: TCode;
|
|
17
|
-
issue?: TIssue;
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface Bindings {
|
|
22
|
-
}
|
|
23
|
-
interface Variables {
|
|
24
|
-
/** Variables */
|
|
25
|
-
[key: string]: unknown;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* HonoEnv is passed to the Hono context to provide types on `ctx.env`.
|
|
29
|
-
*
|
|
30
|
-
* We are using `HonoEnv` to avoid confusion with the Cloudflare types on `Env` -> which cooresponds to `Bindings`
|
|
31
|
-
*
|
|
32
|
-
* * **NOTE** For Cloudflare users, you can declare this in your src/env.d.ts file to get strong
|
|
33
|
-
* typing for `ctx.env`.
|
|
34
|
-
*
|
|
35
|
-
* ```ts
|
|
36
|
-
* declare namespace App {
|
|
37
|
-
* interface Locals extends Runtime {}
|
|
38
|
-
* }
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
interface HonoEnv {
|
|
42
|
-
Bindings: Bindings;
|
|
43
|
-
Variables: Variables;
|
|
44
|
-
}
|
|
45
|
-
type HonoActionSchema = z.ZodType<any, z.ZodTypeDef, any>;
|
|
46
|
-
/**
|
|
47
|
-
* Merge each action key into its route path.
|
|
48
|
-
*
|
|
49
|
-
* Given a map of actions where each `Hono` app defines handlers at `"/"`, this
|
|
50
|
-
* transforms the schema so each action's path becomes `"/${key}"`.
|
|
51
|
-
*
|
|
52
|
-
* Example:
|
|
53
|
-
* ```ts
|
|
54
|
-
* const honoActions: {
|
|
55
|
-
* myAction: Hono<HonoEnv, { '/': { $post: any } }, '/'>
|
|
56
|
-
* anotherAction: Hono<HonoEnv, { '/': { $post: any } }, '/'>
|
|
57
|
-
* }
|
|
58
|
-
*
|
|
59
|
-
* type ActionsWithKeyedPaths = MergeActionKeyIntoPath<typeof honoActions>
|
|
60
|
-
* // => {
|
|
61
|
-
* // myAction: Hono<HonoEnv, { '/myAction': { $post: any } }, '/'>
|
|
62
|
-
* // anotherAction: Hono<HonoEnv, { '/anotherAction': { $post: any } }, '/'>
|
|
63
|
-
* // }
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
type MergeActionKeyIntoPath<TActions extends Record<string, Hono<any, any, any>>> = {
|
|
67
|
-
[K in keyof TActions]: TActions[K] extends Hono<infer TEnv, infer TSchema, infer TBase> ? Hono<TEnv, MergeSchemaPath<TSchema, `/${Extract<K, string>}`>, TBase> : never;
|
|
68
|
-
};
|
|
69
|
-
type HonoActionParams<TSchema extends HonoActionSchema, TReturn, TEnv extends HonoEnv, TContext extends Context<TEnv, any, any>> = {
|
|
70
|
-
schema?: TSchema;
|
|
71
|
-
handler: (params: z.output<TSchema>, context: TContext extends infer Ctx ? Ctx : never) => Promise<TReturn>;
|
|
72
|
-
};
|
|
73
|
-
/**
|
|
74
|
-
* Defines a POST route with Zod validation for the request body.
|
|
75
|
-
*
|
|
76
|
-
* @param schema - The Zod schema for validation (optional).
|
|
77
|
-
* @param handler - The handler function for the action.
|
|
78
|
-
* @returns A Hono app instance with the defined route
|
|
79
|
-
*/
|
|
80
|
-
declare function defineHonoAction<TEnv extends HonoEnv, TSchema extends HonoActionSchema, TReturn, TContext extends Context<TEnv, any, any>>({ schema, handler }: HonoActionParams<TSchema, TReturn, TEnv, TContext>): hono_hono_base.HonoBase<TEnv, {
|
|
81
|
-
"/": {
|
|
82
|
-
$post: {
|
|
83
|
-
input: unknown extends ((undefined extends z.input<TSchema> ? true : false) extends true ? {
|
|
84
|
-
json?: z.input<TSchema> | undefined;
|
|
85
|
-
} : {
|
|
86
|
-
json: z.input<TSchema>;
|
|
87
|
-
}) ? {} : (undefined extends z.input<TSchema> ? true : false) extends true ? {
|
|
88
|
-
json?: z.input<TSchema> | undefined;
|
|
89
|
-
} : {
|
|
90
|
-
json: z.input<TSchema>;
|
|
91
|
-
};
|
|
92
|
-
output: {
|
|
93
|
-
data: null;
|
|
94
|
-
error: {
|
|
95
|
-
message: string;
|
|
96
|
-
code: string;
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
outputFormat: "json";
|
|
100
|
-
status: 500;
|
|
101
|
-
} | {
|
|
102
|
-
input: unknown extends ((undefined extends z.input<TSchema> ? true : false) extends true ? {
|
|
103
|
-
json?: z.input<TSchema> | undefined;
|
|
104
|
-
} : {
|
|
105
|
-
json: z.input<TSchema>;
|
|
106
|
-
}) ? {} : (undefined extends z.input<TSchema> ? true : false) extends true ? {
|
|
107
|
-
json?: z.input<TSchema> | undefined;
|
|
108
|
-
} : {
|
|
109
|
-
json: z.input<TSchema>;
|
|
110
|
-
};
|
|
111
|
-
output: unknown extends (Awaited<TReturn> | null extends bigint | readonly bigint[] ? never : { [K in keyof {
|
|
112
|
-
data: Awaited<TReturn>;
|
|
113
|
-
error: null;
|
|
114
|
-
} as ({
|
|
115
|
-
data: Awaited<TReturn>;
|
|
116
|
-
error: null;
|
|
117
|
-
}[K] extends infer T ? T extends {
|
|
118
|
-
data: Awaited<TReturn>;
|
|
119
|
-
error: null;
|
|
120
|
-
}[K] ? T extends hono_utils_types.InvalidJSONValue ? true : false : never : never) extends true ? never : K]: boolean extends ({
|
|
121
|
-
data: Awaited<TReturn>;
|
|
122
|
-
error: null;
|
|
123
|
-
}[K] extends infer T_1 ? T_1 extends {
|
|
124
|
-
data: Awaited<TReturn>;
|
|
125
|
-
error: null;
|
|
126
|
-
}[K] ? T_1 extends hono_utils_types.InvalidJSONValue ? true : false : never : never) ? hono_utils_types.JSONParsed<{
|
|
127
|
-
data: Awaited<TReturn>;
|
|
128
|
-
error: null;
|
|
129
|
-
}[K], bigint | readonly bigint[]> | undefined : hono_utils_types.JSONParsed<{
|
|
130
|
-
data: Awaited<TReturn>;
|
|
131
|
-
error: null;
|
|
132
|
-
}[K], bigint | readonly bigint[]>; }) ? {} : Awaited<TReturn> | null extends bigint | readonly bigint[] ? never : { [K in keyof {
|
|
133
|
-
data: Awaited<TReturn>;
|
|
134
|
-
error: null;
|
|
135
|
-
} as ({
|
|
136
|
-
data: Awaited<TReturn>;
|
|
137
|
-
error: null;
|
|
138
|
-
}[K] extends infer T ? T extends {
|
|
139
|
-
data: Awaited<TReturn>;
|
|
140
|
-
error: null;
|
|
141
|
-
}[K] ? T extends hono_utils_types.InvalidJSONValue ? true : false : never : never) extends true ? never : K]: boolean extends ({
|
|
142
|
-
data: Awaited<TReturn>;
|
|
143
|
-
error: null;
|
|
144
|
-
}[K] extends infer T_1 ? T_1 extends {
|
|
145
|
-
data: Awaited<TReturn>;
|
|
146
|
-
error: null;
|
|
147
|
-
}[K] ? T_1 extends hono_utils_types.InvalidJSONValue ? true : false : never : never) ? hono_utils_types.JSONParsed<{
|
|
148
|
-
data: Awaited<TReturn>;
|
|
149
|
-
error: null;
|
|
150
|
-
}[K], bigint | readonly bigint[]> | undefined : hono_utils_types.JSONParsed<{
|
|
151
|
-
data: Awaited<TReturn>;
|
|
152
|
-
error: null;
|
|
153
|
-
}[K], bigint | readonly bigint[]>; };
|
|
154
|
-
outputFormat: "json";
|
|
155
|
-
status: 200;
|
|
156
|
-
};
|
|
157
|
-
};
|
|
158
|
-
}, "/", "/">;
|
|
159
|
-
|
|
160
|
-
export { type Bindings, HonoActionError, type HonoEnv, type MergeActionKeyIntoPath, type Variables, defineHonoAction };
|