abret 0.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/index.js ADDED
@@ -0,0 +1,161 @@
1
+ // @bun
2
+ // src/store.ts
3
+ import { AsyncLocalStorage } from "async_hooks";
4
+ var contextStore = new AsyncLocalStorage;
5
+ function createContext(name, ...args) {
6
+ const [defaultValue] = args;
7
+ const id = Symbol(name);
8
+ if (args.length > 0) {
9
+ const Provider = (props) => {
10
+ return props.children;
11
+ };
12
+ Provider._context = { id, defaultValue };
13
+ return {
14
+ id,
15
+ defaultValue,
16
+ Provider
17
+ };
18
+ }
19
+ return id;
20
+ }
21
+ function getContextId(context) {
22
+ if (typeof context === "symbol") {
23
+ return context;
24
+ }
25
+ return context.id;
26
+ }
27
+ function getDefaultValue(context) {
28
+ if (typeof context !== "symbol" && "defaultValue" in context) {
29
+ return context.defaultValue;
30
+ }
31
+ return;
32
+ }
33
+ var setContext = (context, value) => {
34
+ const store = contextStore.getStore();
35
+ if (!store) {
36
+ throw new Error("setContext must be called within a context scope. " + "Ensure you are inside a route handler or use runWithContext.");
37
+ }
38
+ store.set(getContextId(context), value);
39
+ };
40
+ function useContext(context, options) {
41
+ const store = contextStore.getStore();
42
+ const id = getContextId(context);
43
+ const value = store?.get(id);
44
+ if (value !== undefined) {
45
+ return value;
46
+ }
47
+ const defaultVal = getDefaultValue(context);
48
+ if (defaultVal !== undefined) {
49
+ return defaultVal;
50
+ }
51
+ if (options?.required) {
52
+ const name = typeof context === "symbol" ? context.description : context.id.description;
53
+ throw new Error(`Context "${name}" is required but not set`);
54
+ }
55
+ return;
56
+ }
57
+ var hasContext = (context) => {
58
+ const store = contextStore.getStore();
59
+ return store?.has(getContextId(context)) ?? false;
60
+ };
61
+ var clearContext = (context) => {
62
+ const store = contextStore.getStore();
63
+ if (store) {
64
+ store.delete(getContextId(context));
65
+ }
66
+ };
67
+ function runWithContext(fn) {
68
+ const currentStore = contextStore.getStore();
69
+ const newStore = currentStore ? new Map(currentStore) : new Map;
70
+ return contextStore.run(newStore, fn);
71
+ }
72
+ function runWithContextValue(context, value, fn) {
73
+ const currentStore = contextStore.getStore() || new Map;
74
+ const newStore = new Map(currentStore);
75
+ newStore.set(getContextId(context), value);
76
+ return contextStore.run(newStore, fn);
77
+ }
78
+ var getContextStore = () => contextStore;
79
+
80
+ // src/index.ts
81
+ var wrapWithMiddleware = (handler, middlewares) => {
82
+ return (req, server) => {
83
+ return runWithContext(() => {
84
+ if (middlewares.length === 0) {
85
+ return handler(req, server);
86
+ }
87
+ let index = 0;
88
+ const next = () => {
89
+ if (index < middlewares.length) {
90
+ const middleware = middlewares[index++];
91
+ if (middleware)
92
+ return middleware(req, server, next);
93
+ }
94
+ return handler(req, server);
95
+ };
96
+ return next();
97
+ });
98
+ };
99
+ };
100
+ var wrapRouteValue = (value, middlewares) => {
101
+ if (middlewares.length === 0) {
102
+ return value;
103
+ }
104
+ if (value instanceof Response) {
105
+ return wrapWithMiddleware(() => value, middlewares);
106
+ }
107
+ if (typeof value === "function") {
108
+ return wrapWithMiddleware(value, middlewares);
109
+ }
110
+ if (typeof value === "object" && value !== null) {
111
+ const wrappedMethods = {};
112
+ for (const [method, methodHandler] of Object.entries(value)) {
113
+ if (methodHandler instanceof Response) {
114
+ wrappedMethods[method] = wrapWithMiddleware(() => methodHandler, middlewares);
115
+ } else if (typeof methodHandler === "function") {
116
+ wrappedMethods[method] = wrapWithMiddleware(methodHandler, middlewares);
117
+ }
118
+ }
119
+ return wrappedMethods;
120
+ }
121
+ return value;
122
+ };
123
+ var createRoute = (path, value, ...middlewares) => {
124
+ const wrappedValue = wrapRouteValue(value, middlewares);
125
+ return { [path]: wrappedValue };
126
+ };
127
+ var createMiddleware = (fn) => fn;
128
+ var composeMiddlewares = (...middlewares) => {
129
+ return (req, server, finalNext) => {
130
+ let index = 0;
131
+ const next = () => {
132
+ if (index < middlewares.length) {
133
+ const middleware = middlewares[index++];
134
+ if (middleware)
135
+ return middleware(req, server, next);
136
+ }
137
+ return finalNext();
138
+ };
139
+ return next();
140
+ };
141
+ };
142
+ var mergeRoutes = (...routes) => {
143
+ return Object.assign({}, ...routes);
144
+ };
145
+ var createRouteGroup = (prefix, middlewares = []) => {
146
+ return (path, value) => {
147
+ const fullPath = `${prefix}${path}`;
148
+ return createRoute(fullPath, value, ...middlewares);
149
+ };
150
+ };
151
+ export {
152
+ useContext,
153
+ runWithContextValue,
154
+ runWithContext,
155
+ mergeRoutes,
156
+ createRouteGroup,
157
+ createRoute,
158
+ createMiddleware,
159
+ createContext,
160
+ composeMiddlewares
161
+ };
@@ -0,0 +1,38 @@
1
+ export declare class SafeString {
2
+ value: string;
3
+ constructor(value: string);
4
+ toString(): string;
5
+ }
6
+ export declare class AsyncBuffer extends ReadableStream<Uint8Array> {
7
+ private promise;
8
+ constructor(promise: Promise<SafeString>);
9
+ then<TResult1 = SafeString, TResult2 = never>(onfulfilled?: ((value: SafeString) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
10
+ catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null): Promise<SafeString | TResult>;
11
+ finally(onfinally?: (() => void) | null): Promise<SafeString>;
12
+ }
13
+ export declare class VNode {
14
+ tag: string | ((props: any) => any) | typeof Fragment;
15
+ props: Record<string, any>;
16
+ children: any;
17
+ constructor(tag: string | ((props: any) => any) | typeof Fragment, props: Record<string, any>, children: any);
18
+ }
19
+ export type JSXNode = string | number | boolean | bigint | null | undefined | JSXNode[] | Promise<JSXNode> | SafeString | AsyncBuffer | VNode;
20
+ export declare const Fragment: unique symbol;
21
+ export declare function jsx(tag: string | ((props: any) => any) | typeof Fragment, props: Record<string, any>): VNode;
22
+ export declare const jsxs: typeof jsx;
23
+ export declare const jsxDEV: typeof jsx;
24
+ export declare namespace JSX {
25
+ type Element = VNode | SafeString | AsyncBuffer | Promise<SafeString>;
26
+ type ElementType = string | ((props: any) => JSXNode);
27
+ interface IntrinsicElements {
28
+ [elemName: string]: {
29
+ dangerouslySetInnerHTML?: {
30
+ __html: string;
31
+ };
32
+ [key: string]: any;
33
+ };
34
+ }
35
+ interface ElementChildrenAttribute {
36
+ children: unknown;
37
+ }
38
+ }
@@ -0,0 +1 @@
1
+ export * from ".";
@@ -0,0 +1,65 @@
1
+ // @bun
2
+ // src/jsx/index.ts
3
+ class SafeString {
4
+ value;
5
+ constructor(value) {
6
+ this.value = value;
7
+ }
8
+ toString() {
9
+ return this.value;
10
+ }
11
+ }
12
+
13
+ class AsyncBuffer extends ReadableStream {
14
+ promise;
15
+ constructor(promise) {
16
+ super({
17
+ async start(controller) {
18
+ try {
19
+ const result = await promise;
20
+ controller.enqueue(new TextEncoder().encode(result.toString()));
21
+ controller.close();
22
+ } catch (e) {
23
+ controller.error(e);
24
+ }
25
+ }
26
+ });
27
+ this.promise = promise;
28
+ }
29
+ then(onfulfilled, onrejected) {
30
+ return this.promise.then(onfulfilled, onrejected);
31
+ }
32
+ catch(onrejected) {
33
+ return this.promise.catch(onrejected);
34
+ }
35
+ finally(onfinally) {
36
+ return this.promise.finally(onfinally);
37
+ }
38
+ }
39
+
40
+ class VNode {
41
+ tag;
42
+ props;
43
+ children;
44
+ constructor(tag, props, children) {
45
+ this.tag = tag;
46
+ this.props = props;
47
+ this.children = children;
48
+ }
49
+ }
50
+ var Fragment = Symbol("Fragment");
51
+ function jsx(tag, props) {
52
+ const { children, ...rest } = props || {};
53
+ return new VNode(tag, { ...rest, children }, children);
54
+ }
55
+ var jsxs = jsx;
56
+ var jsxDEV = jsx;
57
+ export {
58
+ jsxs,
59
+ jsxDEV,
60
+ jsx,
61
+ VNode,
62
+ SafeString,
63
+ Fragment,
64
+ AsyncBuffer
65
+ };
@@ -0,0 +1 @@
1
+ export * from ".";
@@ -0,0 +1,65 @@
1
+ // @bun
2
+ // src/jsx/index.ts
3
+ class SafeString {
4
+ value;
5
+ constructor(value) {
6
+ this.value = value;
7
+ }
8
+ toString() {
9
+ return this.value;
10
+ }
11
+ }
12
+
13
+ class AsyncBuffer extends ReadableStream {
14
+ promise;
15
+ constructor(promise) {
16
+ super({
17
+ async start(controller) {
18
+ try {
19
+ const result = await promise;
20
+ controller.enqueue(new TextEncoder().encode(result.toString()));
21
+ controller.close();
22
+ } catch (e) {
23
+ controller.error(e);
24
+ }
25
+ }
26
+ });
27
+ this.promise = promise;
28
+ }
29
+ then(onfulfilled, onrejected) {
30
+ return this.promise.then(onfulfilled, onrejected);
31
+ }
32
+ catch(onrejected) {
33
+ return this.promise.catch(onrejected);
34
+ }
35
+ finally(onfinally) {
36
+ return this.promise.finally(onfinally);
37
+ }
38
+ }
39
+
40
+ class VNode {
41
+ tag;
42
+ props;
43
+ children;
44
+ constructor(tag, props, children) {
45
+ this.tag = tag;
46
+ this.props = props;
47
+ this.children = children;
48
+ }
49
+ }
50
+ var Fragment = Symbol("Fragment");
51
+ function jsx(tag, props) {
52
+ const { children, ...rest } = props || {};
53
+ return new VNode(tag, { ...rest, children }, children);
54
+ }
55
+ var jsxs = jsx;
56
+ var jsxDEV = jsx;
57
+ export {
58
+ jsxs,
59
+ jsxDEV,
60
+ jsx,
61
+ VNode,
62
+ SafeString,
63
+ Fragment,
64
+ AsyncBuffer
65
+ };
@@ -0,0 +1,31 @@
1
+ import type { Middleware } from "../..";
2
+ export type ServeStaticOptions = {
3
+ /**
4
+ * Root directory to serve files from.
5
+ * @default "./"
6
+ */
7
+ root?: string;
8
+ /**
9
+ * Path to specific file to serve.
10
+ * If set, this file will be served for all requests.
11
+ */
12
+ path?: string;
13
+ /**
14
+ * Rewrite the request path before file resolution.
15
+ */
16
+ rewriteRequestPath?: (path: string) => string;
17
+ /**
18
+ * Custom mapping of mime types.
19
+ * Extension (without dot) -> Mime Type
20
+ */
21
+ mimes?: Record<string, string>;
22
+ /**
23
+ * Callback when file is not found.
24
+ */
25
+ onNotFound?: (path: string, req: Request) => void;
26
+ };
27
+ /**
28
+ * Middleware to serve static files using Bun.file
29
+ * behaves like hono serveStatic
30
+ */
31
+ export declare const serveStatic: (options?: ServeStaticOptions) => Middleware;
@@ -0,0 +1,40 @@
1
+ // @bun
2
+ // src/middleware/static/index.ts
3
+ import path from "path";
4
+ var serveStatic = (options = {}) => {
5
+ return async (req, _server, next) => {
6
+ if (req.method !== "GET" && req.method !== "HEAD") {
7
+ return next();
8
+ }
9
+ const url = new URL(req.url);
10
+ let filename = options.path ?? url.pathname;
11
+ if (options.rewriteRequestPath) {
12
+ filename = options.rewriteRequestPath(filename);
13
+ }
14
+ const root = options.root ?? "./";
15
+ const validFilename = filename.startsWith("/") ? filename.slice(1) : filename;
16
+ const filePath = path.resolve(root, validFilename);
17
+ const resolvedRoot = path.resolve(root);
18
+ if (!filePath.startsWith(resolvedRoot)) {
19
+ return next();
20
+ }
21
+ const file = Bun.file(filePath);
22
+ if (await file.exists()) {
23
+ const response = new Response(file);
24
+ if (options.mimes) {
25
+ const ext = path.extname(filePath).slice(1);
26
+ if (options.mimes[ext]) {
27
+ response.headers.set("Content-Type", options.mimes[ext]);
28
+ }
29
+ }
30
+ return response;
31
+ }
32
+ if (options.onNotFound) {
33
+ options.onNotFound(filePath, req);
34
+ }
35
+ return next();
36
+ };
37
+ };
38
+ export {
39
+ serveStatic
40
+ };
@@ -0,0 +1,148 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ /**
3
+ * Context type for type-safe context access
4
+ */
5
+ export type Context<T> = symbol & {
6
+ __type: T;
7
+ };
8
+ /**
9
+ * JSX Context interface with Provider component and default value
10
+ */
11
+ export interface ContextWithProvider<T> {
12
+ /**
13
+ * Unique ID for this context
14
+ */
15
+ id: Context<T>;
16
+ /**
17
+ * Default value when context is not set
18
+ */
19
+ defaultValue: T;
20
+ /**
21
+ * Provider component for JSX usage
22
+ */
23
+ Provider: (props: {
24
+ value: T;
25
+ children: unknown;
26
+ }) => any;
27
+ }
28
+ /**
29
+ * Creates a typed context for storing/retrieving values.
30
+ * Works with both request handlers and JSX components.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * import { createContext, useContext, setContext } from "abret/store";
35
+ *
36
+ * // Define context (without default - returns undefined if not set)
37
+ * const UserContext = createContext<{ id: string; name: string }>("user");
38
+ *
39
+ * // Define context (with default value)
40
+ * const ThemeContext = createContext("theme", "light");
41
+ *
42
+ * // In middleware - set context (no req parameter needed!)
43
+ * const authMiddleware = createMiddleware(() => async (req, _server, next) => {
44
+ * const user = await validateToken(req.headers.get("Authorization"));
45
+ * setContext(UserContext, user);
46
+ * return next();
47
+ * });
48
+ *
49
+ * // In handler - use context (no req parameter needed!)
50
+ * const handler = () => {
51
+ * const user = useContext(UserContext);
52
+ * return Response.json({ user });
53
+ * };
54
+ *
55
+ * // In JSX component
56
+ * function UserProfile() {
57
+ * const user = useContext(UserContext);
58
+ * return <div>{user?.name}</div>;
59
+ * }
60
+ * ```
61
+ */
62
+ export declare function createContext<T>(name: string): Context<T>;
63
+ export declare function createContext<T>(name: string, defaultValue: T): ContextWithProvider<T>;
64
+ /**
65
+ * Sets a value in the current context scope.
66
+ * Must be called within a context scope (e.g., inside route handler or runWithContext).
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * setContext(UserContext, { id: "123", name: "John" });
71
+ * ```
72
+ */
73
+ export declare const setContext: <T>(context: Context<T> | ContextWithProvider<T>, value: T) => void;
74
+ /**
75
+ * Options for useContext
76
+ */
77
+ export interface UseContextOptions {
78
+ /**
79
+ * If true, throws an error when context is not set.
80
+ * @default false
81
+ */
82
+ required?: boolean;
83
+ }
84
+ /**
85
+ * Gets a value from the current context scope.
86
+ * Returns undefined if not set, or the default value if context was created with one.
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * // Optional context
91
+ * const user = useContext(UserContext);
92
+ *
93
+ * // Required context (throws if not set)
94
+ * const user = useContext(UserContext, { required: true });
95
+ *
96
+ * // Context with default value
97
+ * const ThemeContext = createContext("theme", "light");
98
+ * const theme = useContext(ThemeContext); // returns "light" if not set
99
+ * ```
100
+ */
101
+ export declare function useContext<T>(context: Context<T>): T | undefined;
102
+ export declare function useContext<T>(context: ContextWithProvider<T>): T;
103
+ export declare function useContext<T>(context: Context<T>, options: {
104
+ required: true;
105
+ }): T;
106
+ /**
107
+ * Checks if a context has been set in the current scope.
108
+ */
109
+ export declare const hasContext: <T>(context: Context<T> | ContextWithProvider<T>) => boolean;
110
+ /**
111
+ * Clears a specific context in the current scope.
112
+ */
113
+ export declare const clearContext: <T>(context: Context<T> | ContextWithProvider<T>) => void;
114
+ /**
115
+ * Runs a function within a new context scope.
116
+ * All setContext/useContext calls within the function will use this scope.
117
+ *
118
+ * This is used internally by the router to wrap each request,
119
+ * but can also be used manually for testing or custom scenarios.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * const result = await runWithContext(async () => {
124
+ * setContext(UserContext, { id: "123", name: "John" });
125
+ * return handleRequest();
126
+ * });
127
+ * ```
128
+ */
129
+ export declare function runWithContext<R>(fn: () => R): R;
130
+ /**
131
+ * Runs a function with a specific context value set.
132
+ * Useful for Provider components in JSX.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * const result = runWithContextValue(ThemeContext, "dark", () => {
137
+ * return useContext(ThemeContext); // returns "dark"
138
+ * });
139
+ * ```
140
+ */
141
+ export declare function runWithContextValue<T, R>(context: Context<T> | ContextWithProvider<T>, value: T, fn: () => R): R;
142
+ /**
143
+ * Gets the raw AsyncLocalStorage instance.
144
+ * Useful for advanced use cases or framework integration.
145
+ *
146
+ * @internal
147
+ */
148
+ export declare const getContextStore: () => AsyncLocalStorage<Map<symbol, unknown>>;
package/dist/store.js ADDED
@@ -0,0 +1,88 @@
1
+ // @bun
2
+ // src/store.ts
3
+ import { AsyncLocalStorage } from "async_hooks";
4
+ var contextStore = new AsyncLocalStorage;
5
+ function createContext(name, ...args) {
6
+ const [defaultValue] = args;
7
+ const id = Symbol(name);
8
+ if (args.length > 0) {
9
+ const Provider = (props) => {
10
+ return props.children;
11
+ };
12
+ Provider._context = { id, defaultValue };
13
+ return {
14
+ id,
15
+ defaultValue,
16
+ Provider
17
+ };
18
+ }
19
+ return id;
20
+ }
21
+ function getContextId(context) {
22
+ if (typeof context === "symbol") {
23
+ return context;
24
+ }
25
+ return context.id;
26
+ }
27
+ function getDefaultValue(context) {
28
+ if (typeof context !== "symbol" && "defaultValue" in context) {
29
+ return context.defaultValue;
30
+ }
31
+ return;
32
+ }
33
+ var setContext = (context, value) => {
34
+ const store = contextStore.getStore();
35
+ if (!store) {
36
+ throw new Error("setContext must be called within a context scope. " + "Ensure you are inside a route handler or use runWithContext.");
37
+ }
38
+ store.set(getContextId(context), value);
39
+ };
40
+ function useContext(context, options) {
41
+ const store = contextStore.getStore();
42
+ const id = getContextId(context);
43
+ const value = store?.get(id);
44
+ if (value !== undefined) {
45
+ return value;
46
+ }
47
+ const defaultVal = getDefaultValue(context);
48
+ if (defaultVal !== undefined) {
49
+ return defaultVal;
50
+ }
51
+ if (options?.required) {
52
+ const name = typeof context === "symbol" ? context.description : context.id.description;
53
+ throw new Error(`Context "${name}" is required but not set`);
54
+ }
55
+ return;
56
+ }
57
+ var hasContext = (context) => {
58
+ const store = contextStore.getStore();
59
+ return store?.has(getContextId(context)) ?? false;
60
+ };
61
+ var clearContext = (context) => {
62
+ const store = contextStore.getStore();
63
+ if (store) {
64
+ store.delete(getContextId(context));
65
+ }
66
+ };
67
+ function runWithContext(fn) {
68
+ const currentStore = contextStore.getStore();
69
+ const newStore = currentStore ? new Map(currentStore) : new Map;
70
+ return contextStore.run(newStore, fn);
71
+ }
72
+ function runWithContextValue(context, value, fn) {
73
+ const currentStore = contextStore.getStore() || new Map;
74
+ const newStore = new Map(currentStore);
75
+ newStore.set(getContextId(context), value);
76
+ return contextStore.run(newStore, fn);
77
+ }
78
+ var getContextStore = () => contextStore;
79
+ export {
80
+ useContext,
81
+ setContext,
82
+ runWithContextValue,
83
+ runWithContext,
84
+ hasContext,
85
+ getContextStore,
86
+ createContext,
87
+ clearContext
88
+ };