@hyperspan/framework 1.0.0-alpha.11 → 1.0.0-alpha.12
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/package.json +1 -1
- package/src/server.test.ts +2 -8
- package/src/server.ts +9 -1
- package/src/types.ts +2 -5
- package/src/utils.test.ts +2 -2
- package/src/utils.ts +1 -1
package/package.json
CHANGED
package/src/server.test.ts
CHANGED
|
@@ -113,7 +113,7 @@ test('createContext() can get and set cookies', () => {
|
|
|
113
113
|
expect(setCookieHeader).toBeTruthy();
|
|
114
114
|
expect(setCookieHeader).toContain('newCookie=newValue');
|
|
115
115
|
|
|
116
|
-
// Test setting a cookie with options (this
|
|
116
|
+
// Test setting a cookie with options (this should NOT overwrite the previous Set-Cookie header)
|
|
117
117
|
context.res.cookies.set('secureCookie', 'secureValue', {
|
|
118
118
|
httpOnly: true,
|
|
119
119
|
secure: true,
|
|
@@ -125,13 +125,7 @@ test('createContext() can get and set cookies', () => {
|
|
|
125
125
|
setCookieHeader = context.res.headers.get('Set-Cookie');
|
|
126
126
|
expect(setCookieHeader).toBeTruthy();
|
|
127
127
|
expect(setCookieHeader).toContain('secureCookie=secureValue');
|
|
128
|
-
expect(setCookieHeader).toContain('
|
|
129
|
-
expect(setCookieHeader).toContain('Secure');
|
|
130
|
-
expect(setCookieHeader).toContain('SameSite=Strict');
|
|
131
|
-
expect(setCookieHeader).toContain('Max-Age=3600');
|
|
132
|
-
|
|
133
|
-
// Verify the previous cookie was overwritten
|
|
134
|
-
expect(setCookieHeader).not.toContain('newCookie=newValue');
|
|
128
|
+
expect(setCookieHeader).toContain('newCookie=newValue');
|
|
135
129
|
|
|
136
130
|
// Test deleting a cookie
|
|
137
131
|
context.res.cookies.delete('sessionId');
|
package/src/server.ts
CHANGED
|
@@ -39,7 +39,15 @@ export function createContext(req: Request, route?: HS.Route): HS.Context {
|
|
|
39
39
|
const headers = new Headers(req.headers);
|
|
40
40
|
const path = route?._path() || '/';
|
|
41
41
|
// @ts-ignore - Bun will put 'params' on the Request object even though it's not standardized
|
|
42
|
-
const params: HS.RouteParamsParser<path> = req?.params || {};
|
|
42
|
+
const params: HS.RouteParamsParser<path> & Record<string, string | undefined> = Object.assign({}, req?.params || {}, route?._config.params || {});
|
|
43
|
+
|
|
44
|
+
// Replace catch-all param with the value from the URL path
|
|
45
|
+
const catchAllParam = Object.keys(params).find(key => key.startsWith('...'));
|
|
46
|
+
if (catchAllParam && path.includes('/*')) {
|
|
47
|
+
const catchAllValue = url.pathname.split(path.replace('/*', '/')).pop();
|
|
48
|
+
params[catchAllParam.replace('...', '')] = catchAllValue;
|
|
49
|
+
delete params[catchAllParam];
|
|
50
|
+
}
|
|
43
51
|
|
|
44
52
|
const merge = (response: Response) => {
|
|
45
53
|
// Convert headers to plain objects and merge (response headers override context headers)
|
package/src/types.ts
CHANGED
|
@@ -77,11 +77,7 @@ export namespace Hyperspan {
|
|
|
77
77
|
|
|
78
78
|
export interface Context {
|
|
79
79
|
vars: Record<string, any>;
|
|
80
|
-
route:
|
|
81
|
-
path: string;
|
|
82
|
-
params: Record<string, string>;
|
|
83
|
-
cssImports?: string[];
|
|
84
|
-
}
|
|
80
|
+
route: RouteConfig;
|
|
85
81
|
req: HSRequest;
|
|
86
82
|
res: HSResponse;
|
|
87
83
|
};
|
|
@@ -94,6 +90,7 @@ export namespace Hyperspan {
|
|
|
94
90
|
export type RouteConfig = {
|
|
95
91
|
name?: string;
|
|
96
92
|
path?: string;
|
|
93
|
+
params?: Record<string, string | undefined>;
|
|
97
94
|
cssImports?: string[];
|
|
98
95
|
};
|
|
99
96
|
export type RouteHandler = (context: Hyperspan.Context) => unknown;
|
package/src/utils.test.ts
CHANGED
|
@@ -149,13 +149,13 @@ describe('parsePath', () => {
|
|
|
149
149
|
test('parsePath handles catch-all param with spread', () => {
|
|
150
150
|
const result = parsePath('users/[...slug]');
|
|
151
151
|
expect(result.path).toBe('/users/*');
|
|
152
|
-
expect(result.params).toEqual(['slug']);
|
|
152
|
+
expect(result.params).toEqual(['...slug']);
|
|
153
153
|
});
|
|
154
154
|
|
|
155
155
|
test('parsePath handles catch-all param at root', () => {
|
|
156
156
|
const result = parsePath('[...slug]');
|
|
157
157
|
expect(result.path).toBe('/*');
|
|
158
|
-
expect(result.params).toEqual(['slug']);
|
|
158
|
+
expect(result.params).toEqual(['...slug']);
|
|
159
159
|
});
|
|
160
160
|
|
|
161
161
|
test('parsePath preserves param names in path but converts format', () => {
|
package/src/utils.ts
CHANGED
|
@@ -33,7 +33,7 @@ export function parsePath(urlPath: string): { path: string, params: string[] } {
|
|
|
33
33
|
// Dynamic params
|
|
34
34
|
if (ROUTE_SEGMENT_REGEX.test(urlPath)) {
|
|
35
35
|
urlPath = urlPath.replace(ROUTE_SEGMENT_REGEX, (match: string) => {
|
|
36
|
-
const paramName = match.replace(/[^a-zA-Z_\.]+/g, '')
|
|
36
|
+
const paramName = match.replace(/[^a-zA-Z_\.]+/g, '');
|
|
37
37
|
params.push(paramName);
|
|
38
38
|
|
|
39
39
|
if (match.includes('...')) {
|