solidstep 0.3.4 → 0.4.0
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 +1094 -829
- package/index.d.ts.map +1 -1
- package/index.js +20 -3
- package/package.json +143 -72
- package/server.d.ts.map +1 -1
- package/server.js +306 -216
- package/utils/cache.d.ts.map +1 -1
- package/utils/cache.js +8 -19
- package/utils/components/form.d.ts +47 -0
- package/utils/components/form.d.ts.map +1 -0
- package/utils/components/form.js +95 -0
- package/utils/csp.d.ts.map +1 -1
- package/utils/csp.js +0 -2
- package/utils/hooks/action-state.d.ts +19 -1
- package/utils/hooks/action-state.d.ts.map +1 -1
- package/utils/hooks/action-state.js +24 -4
- package/utils/hooks/form-status.d.ts +12 -0
- package/utils/hooks/form-status.d.ts.map +1 -0
- package/utils/hooks/form-status.js +16 -0
- package/utils/instrumentation-noop.d.ts +3 -0
- package/utils/instrumentation-noop.d.ts.map +1 -0
- package/utils/instrumentation-noop.js +3 -0
- package/utils/instrumentation.d.ts +94 -0
- package/utils/instrumentation.d.ts.map +1 -0
- package/utils/instrumentation.js +132 -0
- package/utils/loader.d.ts.map +1 -1
- package/utils/loader.js +5 -11
- package/utils/middleware.d.ts +43 -0
- package/utils/middleware.d.ts.map +1 -0
- package/utils/middleware.js +48 -0
- package/utils/path-router.js +10 -10
- package/utils/router.d.ts.map +1 -1
- package/utils/router.js +3 -1
- package/utils/server-action.server.d.ts.map +1 -1
- package/utils/server-action.server.js +56 -22
package/utils/cache.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../utils/cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../utils/cache.ts"],"names":[],"mappings":"AAsCA,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,KAAK,MAAM,KAAG,CAAC,GAAG,IAe7C,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,KAAK,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,MAAM,SA0BhE,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,SAU1C,CAAC;AAEF,eAAO,MAAM,aAAa,YAGzB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,SAS1C,CAAC"}
|
package/utils/cache.js
CHANGED
|
@@ -6,38 +6,27 @@ let tail;
|
|
|
6
6
|
const moveToFront = (node) => {
|
|
7
7
|
if (node === head)
|
|
8
8
|
return;
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
node.prev.next = node.next;
|
|
9
|
+
// node.prev is always defined here: node !== head guarantees a predecessor
|
|
10
|
+
node.prev.next = node.next;
|
|
12
11
|
if (node.next)
|
|
13
12
|
node.next.prev = node.prev;
|
|
14
13
|
if (node === tail)
|
|
15
14
|
tail = node.prev;
|
|
16
|
-
//
|
|
15
|
+
// head is always defined here: there are ≥2 nodes when moveToFront is reached
|
|
17
16
|
node.prev = undefined;
|
|
18
17
|
node.next = head;
|
|
19
|
-
|
|
20
|
-
head.prev = node;
|
|
18
|
+
head.prev = node;
|
|
21
19
|
head = node;
|
|
22
|
-
if (!tail)
|
|
23
|
-
tail = node;
|
|
24
20
|
};
|
|
21
|
+
// Only called when cacheMap.size > MAX_CACHE_ENTRIES, so tail and tail.prev are always defined.
|
|
25
22
|
const removeTail = () => {
|
|
26
|
-
if (!tail)
|
|
27
|
-
return;
|
|
28
23
|
cacheMap.delete(tail.key);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
tail = tail.prev;
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
// Only one node
|
|
35
|
-
head = tail = undefined;
|
|
36
|
-
}
|
|
24
|
+
tail.prev.next = undefined;
|
|
25
|
+
tail = tail.prev;
|
|
37
26
|
};
|
|
38
27
|
export const getCache = (key) => {
|
|
39
28
|
const entry = cacheMap.get(key);
|
|
40
|
-
if (!entry
|
|
29
|
+
if (!entry)
|
|
41
30
|
return null;
|
|
42
31
|
if (entry.expiresAt && entry.expiresAt < performance.now()) {
|
|
43
32
|
cacheMap.delete(key);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A server action function created by the `'use server'` directive.
|
|
3
|
+
* Has a `.url` property pointing to the `/_server` endpoint.
|
|
4
|
+
*/
|
|
5
|
+
export type ServerActionFn = {
|
|
6
|
+
(...args: any[]): any;
|
|
7
|
+
url?: string;
|
|
8
|
+
};
|
|
9
|
+
export type FormProps = {
|
|
10
|
+
/** Server action or wrapped formAction from useActionState */
|
|
11
|
+
action: ServerActionFn | ((formData: FormData) => void);
|
|
12
|
+
/** Form content */
|
|
13
|
+
children?: any;
|
|
14
|
+
/** Additional HTML form attributes are spread onto the <form> element */
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Enhanced `<form>` component that submits via server actions.
|
|
19
|
+
*
|
|
20
|
+
* - Intercepts form submission and calls the server action with `FormData`
|
|
21
|
+
* - Provides `FormStatusContext` for nested `useFormStatus()` calls
|
|
22
|
+
* - Supports progressive enhancement: when JS is disabled, the form
|
|
23
|
+
* submits natively to the server action URL (if the action has one)
|
|
24
|
+
* - Supports `formAction` overrides on submitter elements (buttons)
|
|
25
|
+
*
|
|
26
|
+
* Rendered with Solid's isomorphic `Dynamic`, so it server-renders and hydrates
|
|
27
|
+
* correctly (no client-only primitives are evaluated on the server).
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* import { Form } from 'solidstep/form';
|
|
32
|
+
* import { createInvoice } from './actions';
|
|
33
|
+
*
|
|
34
|
+
* export default function Page() {
|
|
35
|
+
* return (
|
|
36
|
+
* <Form action={createInvoice}>
|
|
37
|
+
* <input name="amount" />
|
|
38
|
+
* <button type="submit">Create</button>
|
|
39
|
+
* </Form>
|
|
40
|
+
* );
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare const Form: (props: FormProps) => import("solid-js").JSX.Element;
|
|
45
|
+
export { Form };
|
|
46
|
+
export default Form;
|
|
47
|
+
//# sourceMappingURL=form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../utils/components/form.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IACzB,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACpB,8DAA8D;IAC9D,MAAM,EAAE,cAAc,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC;IACxD,mBAAmB;IACnB,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,yEAAyE;IACzE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,QAAA,MAAM,IAAI,GAAI,OAAO,SAAS,mCA0E7B,CAAC;AAEF,OAAO,EAAE,IAAI,EAAE,CAAC;AAChB,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createComponent, createSignal, splitProps, mergeProps } from 'solid-js';
|
|
2
|
+
import { Dynamic } from 'solid-js/web';
|
|
3
|
+
import { FormStatusContext, } from '../hooks/form-status';
|
|
4
|
+
/**
|
|
5
|
+
* Enhanced `<form>` component that submits via server actions.
|
|
6
|
+
*
|
|
7
|
+
* - Intercepts form submission and calls the server action with `FormData`
|
|
8
|
+
* - Provides `FormStatusContext` for nested `useFormStatus()` calls
|
|
9
|
+
* - Supports progressive enhancement: when JS is disabled, the form
|
|
10
|
+
* submits natively to the server action URL (if the action has one)
|
|
11
|
+
* - Supports `formAction` overrides on submitter elements (buttons)
|
|
12
|
+
*
|
|
13
|
+
* Rendered with Solid's isomorphic `Dynamic`, so it server-renders and hydrates
|
|
14
|
+
* correctly (no client-only primitives are evaluated on the server).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* import { Form } from 'solidstep/form';
|
|
19
|
+
* import { createInvoice } from './actions';
|
|
20
|
+
*
|
|
21
|
+
* export default function Page() {
|
|
22
|
+
* return (
|
|
23
|
+
* <Form action={createInvoice}>
|
|
24
|
+
* <input name="amount" />
|
|
25
|
+
* <button type="submit">Create</button>
|
|
26
|
+
* </Form>
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
const Form = (props) => {
|
|
32
|
+
const [local, others] = splitProps(props, ['action', 'children']);
|
|
33
|
+
const [pending, setPending] = createSignal(false);
|
|
34
|
+
const [formData, setFormData] = createSignal(null);
|
|
35
|
+
const actionUrl = () => {
|
|
36
|
+
const action = local.action;
|
|
37
|
+
if (typeof action === 'function' && 'url' in action) {
|
|
38
|
+
return action.url || null;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
};
|
|
42
|
+
const contextValue = {
|
|
43
|
+
pending,
|
|
44
|
+
data: formData,
|
|
45
|
+
method: () => 'POST',
|
|
46
|
+
action: actionUrl,
|
|
47
|
+
};
|
|
48
|
+
const handleSubmit = async (e) => {
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
const form = e.currentTarget;
|
|
51
|
+
const submitter = e.submitter;
|
|
52
|
+
const data = new FormData(form, submitter);
|
|
53
|
+
// Check for formAction override on submitter element
|
|
54
|
+
let action = local.action;
|
|
55
|
+
if (submitter && '__serverAction' in submitter) {
|
|
56
|
+
action = submitter.__serverAction;
|
|
57
|
+
}
|
|
58
|
+
setFormData(data);
|
|
59
|
+
setPending(true);
|
|
60
|
+
try {
|
|
61
|
+
await action(data);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
console.error('Form action error:', error);
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
setPending(false);
|
|
68
|
+
setFormData(null);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
// `Dynamic` renders a real <form> on both server and client. The `onSubmit`
|
|
72
|
+
// handler is attached only on the client (ignored during SSR); `method` and
|
|
73
|
+
// `action` are emitted as attributes for the no-JS progressive-enhancement
|
|
74
|
+
// fallback. Remaining props (class, id, data-*, ...) are spread through.
|
|
75
|
+
const formProps = mergeProps({
|
|
76
|
+
component: 'form',
|
|
77
|
+
method: 'POST',
|
|
78
|
+
onSubmit: handleSubmit,
|
|
79
|
+
get action() {
|
|
80
|
+
return actionUrl() ?? undefined;
|
|
81
|
+
},
|
|
82
|
+
}, others, {
|
|
83
|
+
get children() {
|
|
84
|
+
return local.children;
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
return createComponent(FormStatusContext.Provider, {
|
|
88
|
+
value: contextValue,
|
|
89
|
+
get children() {
|
|
90
|
+
return createComponent(Dynamic, formProps);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
export { Form };
|
|
95
|
+
export default Form;
|
package/utils/csp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csp.d.ts","sourceRoot":"","sources":["../../utils/csp.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,KAAK,aAAa,GACZ,aAAa,GACb,YAAY,GACZ,WAAW,GACX,gBAAgB,GAChB,SAAS,GACT,UAAU,GACV,aAAa,GACb,WAAW,GACX,YAAY,GACZ,WAAW,GACX,iBAAiB,GACjB,UAAU,GACV,aAAa,GACb,YAAY,GACZ,cAAc,CAAC;AAErB,KAAK,MAAM,GACL,QAAQ,GACR,QAAQ,GACR,iBAAiB,GACjB,eAAe,GACf,iBAAiB,GACjB,oBAAoB,GACpB,kBAAkB,GAClB,OAAO,GACP,OAAO,GACP,aAAa,GACb,KAAK,GACL,MAAM,GACN,QAAQ,GACR,OAAO,GACP,MAAM,CAAC;AAEb,KAAK,YAAY,GAAG;IAChB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC3C,CAAC;AAEF,KAAK,SAAS,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;AAG7C,QAAA,MAAM,eAAe,GAAI,MAAM,aAAa,EAAE,SAAS,MAAM,EAAE,KAAG,YAGhE,CAAC;AAEH,QAAA,MAAM,SAAS,GAAI,WAAW,YAAY,EAAE,QAAQ,MAAM,KAAG,YAG3D,CAAC;AAEH,QAAA,MAAM,YAAY,GAAI,WAAW,YAAY,EAAE,QAAQ,MAAM,KAAG,YAG9D,CAAC;AAEH,QAAA,MAAM,UAAU,GAAI,WAAW,YAAY,EAAE,SAAS,MAAM,EAAE,KAAG,YAG/D,CAAC;AAGH,QAAA,MAAM,YAAY,GAAI,QAAQ,SAAS,EAAE,WAAW,YAAY,KAAG,SAQlE,CAAC;AAEF,QAAA,MAAM,eAAe,GACjB,QAAQ,SAAS,EACjB,MAAM,aAAa,EACnB,SAAS,CAAC,SAAS,EAAE,YAAY,KAAK,YAAY,KACnD,SAMF,CAAC;AAEF,QAAA,MAAM,eAAe,GAAI,QAAQ,SAAS,EAAE,MAAM,aAAa,KAAG,SACzB,CAAC;AAE1C,QAAA,MAAM,YAAY,GAAI,QAAQ,SAAS,EAAE,MAAM,aAAa,KAAG,YAAY,GAAG,SACvC,CAAC;AAaxC,QAAA,MAAM,aAAa,GAAI,GAAG,UAAU,SAAS,EAAE,KAAG,SAejD,CAAC;AAGF,QAAA,MAAM,kBAAkB,GAAI,WAAW,YAAY,KAAG,MACA,CAAC;AAEvD,QAAA,MAAM,eAAe,GAAI,QAAQ,SAAS,KAAG,MACA,CAAC;AAE9C,QAAA,MAAM,cAAc,GAAI,cAAc,MAAM,KAAG,YAAY,GAAG,
|
|
1
|
+
{"version":3,"file":"csp.d.ts","sourceRoot":"","sources":["../../utils/csp.ts"],"names":[],"mappings":"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"}
|
package/utils/csp.js
CHANGED
|
@@ -61,8 +61,6 @@ const serializeDirective = (directive) => `${directive.name} ${directive.sources
|
|
|
61
61
|
const serializePolicy = (policy) => policy.map(serializeDirective).join('; ');
|
|
62
62
|
const parseDirective = (directiveStr) => {
|
|
63
63
|
const parts = directiveStr.trim().split(/\s+/);
|
|
64
|
-
if (parts.length < 1)
|
|
65
|
-
return null;
|
|
66
64
|
const [name, ...sources] = parts;
|
|
67
65
|
return createDirective(name, sources);
|
|
68
66
|
};
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import { type Accessor } from 'solid-js';
|
|
2
|
+
export type UseActionStateReturn<T> = [
|
|
3
|
+
state: Accessor<T>,
|
|
4
|
+
formAction: (formData: FormData) => void,
|
|
5
|
+
pending: Accessor<boolean>,
|
|
6
|
+
error: Accessor<Error | null>
|
|
7
|
+
];
|
|
8
|
+
/**
|
|
9
|
+
* Wraps a server action for use with `<Form>`.
|
|
10
|
+
*
|
|
11
|
+
* The server action receives `(prevState, formData)` and returns the new state.
|
|
12
|
+
* The returned `formAction` can be passed directly to `<Form action={formAction}>`.
|
|
13
|
+
*
|
|
14
|
+
* @param action - Server action: `(prevState: T, formData: FormData) => Promise<T>`
|
|
15
|
+
* @param initialState - Initial state value before any submission.
|
|
16
|
+
* @returns `[state, formAction, pending, error]`
|
|
17
|
+
*/
|
|
18
|
+
declare const useActionState: <T>(action: (prevState: T, formData: FormData) => Promise<T>, initialState: T) => UseActionStateReturn<T>;
|
|
19
|
+
export { useActionState };
|
|
2
20
|
export default useActionState;
|
|
3
21
|
//# sourceMappingURL=action-state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-state.d.ts","sourceRoot":"","sources":["../../../utils/hooks/action-state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"action-state.d.ts","sourceRoot":"","sources":["../../../utils/hooks/action-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEvD,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAAI;IAClC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;IAClB,UAAU,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI;IACxC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF;;;;;;;;;GASG;AACH,QAAA,MAAM,cAAc,GAAI,CAAC,EACrB,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,EACxD,cAAc,CAAC,KAChB,oBAAoB,CAAC,CAAC,CAqBxB,CAAC;AAEF,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,eAAe,cAAc,CAAC"}
|
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
import { createSignal } from 'solid-js';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Wraps a server action for use with `<Form>`.
|
|
4
|
+
*
|
|
5
|
+
* The server action receives `(prevState, formData)` and returns the new state.
|
|
6
|
+
* The returned `formAction` can be passed directly to `<Form action={formAction}>`.
|
|
7
|
+
*
|
|
8
|
+
* @param action - Server action: `(prevState: T, formData: FormData) => Promise<T>`
|
|
9
|
+
* @param initialState - Initial state value before any submission.
|
|
10
|
+
* @returns `[state, formAction, pending, error]`
|
|
11
|
+
*/
|
|
12
|
+
const useActionState = (action, initialState) => {
|
|
13
|
+
const [state, setState] = createSignal(initialState);
|
|
3
14
|
const [isPending, setIsPending] = createSignal(false);
|
|
4
|
-
const
|
|
15
|
+
const [error, setError] = createSignal(null);
|
|
16
|
+
const formAction = (formData) => {
|
|
5
17
|
setIsPending(true);
|
|
6
|
-
|
|
18
|
+
setError(null);
|
|
19
|
+
Promise.resolve(action(state(), formData))
|
|
20
|
+
.then((result) => {
|
|
21
|
+
setState(() => result);
|
|
22
|
+
})
|
|
23
|
+
.catch((err) => {
|
|
24
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
25
|
+
})
|
|
7
26
|
.finally(() => {
|
|
8
27
|
setIsPending(false);
|
|
9
28
|
});
|
|
10
29
|
};
|
|
11
|
-
return [isPending,
|
|
30
|
+
return [state, formAction, isPending, error];
|
|
12
31
|
};
|
|
32
|
+
export { useActionState };
|
|
13
33
|
export default useActionState;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Accessor } from 'solid-js';
|
|
2
|
+
export type FormStatusContextValue = {
|
|
3
|
+
pending: Accessor<boolean>;
|
|
4
|
+
data: Accessor<FormData | null>;
|
|
5
|
+
method: Accessor<string>;
|
|
6
|
+
action: Accessor<string | null>;
|
|
7
|
+
};
|
|
8
|
+
export declare const FormStatusContext: import("solid-js").Context<FormStatusContextValue | undefined>;
|
|
9
|
+
declare const useFormStatus: () => FormStatusContextValue;
|
|
10
|
+
export { useFormStatus };
|
|
11
|
+
export default useFormStatus;
|
|
12
|
+
//# sourceMappingURL=form-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-status.d.ts","sourceRoot":"","sources":["../../../utils/hooks/form-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpE,MAAM,MAAM,sBAAsB,GAAG;IACjC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,IAAI,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAChC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,MAAM,EAAE,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,iBAAiB,gEAA0C,CAAC;AAEzE,QAAA,MAAM,aAAa,QAAO,sBAWzB,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,CAAC;AACzB,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createContext, useContext } from 'solid-js';
|
|
2
|
+
export const FormStatusContext = createContext();
|
|
3
|
+
const useFormStatus = () => {
|
|
4
|
+
const ctx = useContext(FormStatusContext);
|
|
5
|
+
if (!ctx) {
|
|
6
|
+
return {
|
|
7
|
+
pending: () => false,
|
|
8
|
+
data: () => null,
|
|
9
|
+
method: () => 'GET',
|
|
10
|
+
action: () => null,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return ctx;
|
|
14
|
+
};
|
|
15
|
+
export { useFormStatus };
|
|
16
|
+
export default useFormStatus;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentation-noop.d.ts","sourceRoot":"","sources":["../../utils/instrumentation-noop.ts"],"names":[],"mappings":";AAEA,wBAAkB"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export interface RequestContext {
|
|
2
|
+
/** The matched route path pattern (e.g., "/posts/[id]") */
|
|
3
|
+
routePath: string;
|
|
4
|
+
/** The actual URL pathname (e.g., "/posts/123") */
|
|
5
|
+
pathname: string;
|
|
6
|
+
/** Type of route being handled */
|
|
7
|
+
routeType: 'page' | 'api' | 'static' | 'not-found' | 'error' | 'server-action' | 'unknown';
|
|
8
|
+
/** Route parameters extracted from the path */
|
|
9
|
+
params: Record<string, string | string[]>;
|
|
10
|
+
/** URL search parameters */
|
|
11
|
+
searchParams: Record<string, string>;
|
|
12
|
+
/** High-resolution timestamp when request started */
|
|
13
|
+
startTime: number;
|
|
14
|
+
/** Custom metadata attached to the request */
|
|
15
|
+
metadata: Record<string, unknown>;
|
|
16
|
+
/** Unix timestamp (milliseconds) when request started */
|
|
17
|
+
startTimeEpoch: number;
|
|
18
|
+
}
|
|
19
|
+
export interface ResponseContext extends RequestContext {
|
|
20
|
+
/** HTTP status code */
|
|
21
|
+
statusCode: number;
|
|
22
|
+
/** Duration in milliseconds since request started */
|
|
23
|
+
duration: number;
|
|
24
|
+
}
|
|
25
|
+
export interface ServerInfo {
|
|
26
|
+
/** Full server URL (e.g., "http://localhost:3001") */
|
|
27
|
+
url: string;
|
|
28
|
+
/** Port number */
|
|
29
|
+
port: number;
|
|
30
|
+
/** Host (e.g., "localhost" or "0.0.0.0") */
|
|
31
|
+
host: string;
|
|
32
|
+
/** Current environment */
|
|
33
|
+
env: 'development' | 'production';
|
|
34
|
+
}
|
|
35
|
+
/** Called once during server startup. Errors will prevent server from starting. */
|
|
36
|
+
export type RegisterFn = () => void | Promise<void>;
|
|
37
|
+
/** Called before each request is processed */
|
|
38
|
+
export type OnRequestFn = (request: Request, context: RequestContext) => void | Promise<void>;
|
|
39
|
+
/** Called when response is ready but before streaming starts */
|
|
40
|
+
export type OnResponseStartFn = (request: Request, response: Response, context: ResponseContext) => void | Promise<void>;
|
|
41
|
+
/** Called after response stream is complete */
|
|
42
|
+
export type OnResponseEndFn = (request: Request, context: ResponseContext) => void | Promise<void>;
|
|
43
|
+
/** Called when server is fully ready and listening */
|
|
44
|
+
export type OnServerReadyFn = (server: ServerInfo) => void | Promise<void>;
|
|
45
|
+
/** Called when server is shutting down */
|
|
46
|
+
export type OnShutdownFn = () => void | Promise<void>;
|
|
47
|
+
/** Called when an error occurs during request processing */
|
|
48
|
+
export type OnRequestErrorFn = (error: Error, context: RequestContext) => void | Promise<void>;
|
|
49
|
+
export interface InstrumentationModule {
|
|
50
|
+
register?: RegisterFn;
|
|
51
|
+
onRequest?: OnRequestFn;
|
|
52
|
+
onResponseStart?: OnResponseStartFn;
|
|
53
|
+
onResponseEnd?: OnResponseEndFn;
|
|
54
|
+
onServerReady?: OnServerReadyFn;
|
|
55
|
+
onShutdown?: OnShutdownFn;
|
|
56
|
+
onRequestError?: OnRequestErrorFn;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Define instrumentation with full type safety.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* // instrumentation.ts
|
|
64
|
+
* import { defineInstrumentation } from './utils/instrumentation';
|
|
65
|
+
*
|
|
66
|
+
* export default defineInstrumentation({
|
|
67
|
+
* async register() {
|
|
68
|
+
* // Initialize telemetry
|
|
69
|
+
* },
|
|
70
|
+
* async onRequest(request, context) {
|
|
71
|
+
* console.log(`${request.method} ${context.pathname}`);
|
|
72
|
+
* },
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function defineInstrumentation(config: InstrumentationModule): InstrumentationModule;
|
|
77
|
+
/**
|
|
78
|
+
* Load the user's instrumentation module.
|
|
79
|
+
* Called once during server startup.
|
|
80
|
+
*/
|
|
81
|
+
export declare function loadInstrumentation(): Promise<InstrumentationModule | null>;
|
|
82
|
+
/**
|
|
83
|
+
* Get the loaded instrumentation module.
|
|
84
|
+
* Returns null if not loaded or no instrumentation file exists.
|
|
85
|
+
*/
|
|
86
|
+
export declare function getInstrumentation(): InstrumentationModule | null;
|
|
87
|
+
/**
|
|
88
|
+
* Safely execute a hook, catching and logging any errors.
|
|
89
|
+
* Used for request/response hooks where we don't want to fail the request.
|
|
90
|
+
*/
|
|
91
|
+
export declare function safeExecuteHook<T extends (...args: any[]) => any>(hookName: string, hook: T | undefined, ...args: Parameters<T>): Promise<void>;
|
|
92
|
+
export declare function createRequestContext(request: Request, overrides?: Partial<RequestContext>): RequestContext;
|
|
93
|
+
export declare function createResponseContext(requestContext: RequestContext, statusCode: number): ResponseContext;
|
|
94
|
+
//# sourceMappingURL=instrumentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../utils/instrumentation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// utils/instrumentation.ts
|
|
2
|
+
// Instrumentation types, helpers, and loader for SolidStep telemetry
|
|
3
|
+
// Instrumentation types, helpers, and loader for SolidStep telemetry
|
|
4
|
+
// ============================================
|
|
5
|
+
// Helper for Type-Safe Definition
|
|
6
|
+
// ============================================
|
|
7
|
+
/**
|
|
8
|
+
* Define instrumentation with full type safety.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* // instrumentation.ts
|
|
13
|
+
* import { defineInstrumentation } from './utils/instrumentation';
|
|
14
|
+
*
|
|
15
|
+
* export default defineInstrumentation({
|
|
16
|
+
* async register() {
|
|
17
|
+
* // Initialize telemetry
|
|
18
|
+
* },
|
|
19
|
+
* async onRequest(request, context) {
|
|
20
|
+
* console.log(`${request.method} ${context.pathname}`);
|
|
21
|
+
* },
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function defineInstrumentation(config) {
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
28
|
+
// ============================================
|
|
29
|
+
// Internal State & Loader
|
|
30
|
+
// ============================================
|
|
31
|
+
let instrumentationModule = null;
|
|
32
|
+
let initPromise = null;
|
|
33
|
+
let initError = null;
|
|
34
|
+
/**
|
|
35
|
+
* Load the user's instrumentation module.
|
|
36
|
+
* Called once during server startup.
|
|
37
|
+
*/
|
|
38
|
+
export async function loadInstrumentation() {
|
|
39
|
+
if (initPromise) {
|
|
40
|
+
return initPromise;
|
|
41
|
+
}
|
|
42
|
+
initPromise = (async () => {
|
|
43
|
+
try {
|
|
44
|
+
// This import is resolved at build time via alias
|
|
45
|
+
// @ts-expect-error - resolved at build time by Vite alias
|
|
46
|
+
const module = await import('instrumentation');
|
|
47
|
+
// Support both default export and named exports
|
|
48
|
+
if (module.default && typeof module.default === 'object') {
|
|
49
|
+
instrumentationModule = module.default;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Named exports
|
|
53
|
+
instrumentationModule = {
|
|
54
|
+
register: module.register,
|
|
55
|
+
onRequest: module.onRequest,
|
|
56
|
+
onResponseStart: module.onResponseStart,
|
|
57
|
+
onResponseEnd: module.onResponseEnd,
|
|
58
|
+
onServerReady: module.onServerReady,
|
|
59
|
+
onShutdown: module.onShutdown,
|
|
60
|
+
onRequestError: module.onRequestError,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return instrumentationModule;
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
// Check if it's a "module not found" error (no instrumentation file)
|
|
67
|
+
if (e.code === 'ERR_MODULE_NOT_FOUND' ||
|
|
68
|
+
e.message?.includes('Cannot find module')) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
// Re-throw other errors (syntax errors, etc.)
|
|
72
|
+
initError = e;
|
|
73
|
+
throw e;
|
|
74
|
+
}
|
|
75
|
+
})();
|
|
76
|
+
try {
|
|
77
|
+
return await initPromise;
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
if (initError)
|
|
81
|
+
throw initError;
|
|
82
|
+
throw e;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get the loaded instrumentation module.
|
|
87
|
+
* Returns null if not loaded or no instrumentation file exists.
|
|
88
|
+
*/
|
|
89
|
+
export function getInstrumentation() {
|
|
90
|
+
return instrumentationModule;
|
|
91
|
+
}
|
|
92
|
+
// ============================================
|
|
93
|
+
// Safe Hook Executors (for request lifecycle)
|
|
94
|
+
// ============================================
|
|
95
|
+
/**
|
|
96
|
+
* Safely execute a hook, catching and logging any errors.
|
|
97
|
+
* Used for request/response hooks where we don't want to fail the request.
|
|
98
|
+
*/
|
|
99
|
+
export async function safeExecuteHook(hookName, hook, ...args) {
|
|
100
|
+
if (!hook)
|
|
101
|
+
return;
|
|
102
|
+
try {
|
|
103
|
+
await hook(...args);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error(`[instrumentation] Error in ${hookName} hook:`, error);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// ============================================
|
|
110
|
+
// Request Context Builder
|
|
111
|
+
// ============================================
|
|
112
|
+
export function createRequestContext(request, overrides = {}) {
|
|
113
|
+
const url = new URL(request.url);
|
|
114
|
+
return {
|
|
115
|
+
routePath: 'unknown',
|
|
116
|
+
pathname: url.pathname,
|
|
117
|
+
routeType: 'unknown',
|
|
118
|
+
params: {},
|
|
119
|
+
searchParams: Object.fromEntries(url.searchParams),
|
|
120
|
+
startTime: performance.now(),
|
|
121
|
+
metadata: {},
|
|
122
|
+
startTimeEpoch: Date.now(),
|
|
123
|
+
...overrides,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
export function createResponseContext(requestContext, statusCode) {
|
|
127
|
+
return {
|
|
128
|
+
...requestContext,
|
|
129
|
+
statusCode,
|
|
130
|
+
duration: performance.now() - requestContext.startTime,
|
|
131
|
+
};
|
|
132
|
+
}
|
package/utils/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../utils/loader.ts"],"names":[],"mappings":"AAEA,KAAK,cAAc,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAE3D,KAAK,aAAa,GAAG;IACjB,IAAI,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;CACjC,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,EAAE,QAAQ,cAAc,CAAC,CAAC,CAAC,EAAE,UAAU,aAAa;uBAE9C,OAAO;;;;;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../utils/loader.ts"],"names":[],"mappings":"AAEA,KAAK,cAAc,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAE3D,KAAK,aAAa,GAAG;IACjB,IAAI,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;CACjC,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,EAAE,QAAQ,cAAc,CAAC,CAAC,CAAC,EAAE,UAAU,aAAa;uBAE9C,OAAO;;;;;QAe1C,CAAC;AAEF,MAAM,MAAM,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,KAAK,GAAG,CAAA;CAAE,GAC7F,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,KAAK,GACtE,KAAK,CAAC"}
|
package/utils/loader.js
CHANGED
|
@@ -2,17 +2,11 @@ import { isServer } from 'solid-js/web';
|
|
|
2
2
|
export const defineLoader = (loader, options) => {
|
|
3
3
|
if (isServer) {
|
|
4
4
|
const fn = async (request) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
catch (error) {
|
|
13
|
-
console.error('Error in loader:', error);
|
|
14
|
-
throw error; // Re-throw to allow error handling upstream
|
|
15
|
-
}
|
|
5
|
+
const loaderData = await loader(request);
|
|
6
|
+
return {
|
|
7
|
+
data: loaderData,
|
|
8
|
+
type: options?.type || 'sequential',
|
|
9
|
+
};
|
|
16
10
|
};
|
|
17
11
|
return {
|
|
18
12
|
loader: fn,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type H3Event } from 'vinxi/http';
|
|
2
|
+
/**
|
|
3
|
+
* Runs before the matched route handler. Return a `Response` (or call
|
|
4
|
+
* `event.respondWith(...)`) to short-circuit the chain — later middleware and
|
|
5
|
+
* the route handler are skipped.
|
|
6
|
+
*/
|
|
7
|
+
export type MiddlewareRequestHandler = (event: H3Event) => void | Response | Promise<void | Response>;
|
|
8
|
+
/**
|
|
9
|
+
* Runs after the route handler, before the response is sent. Receives the
|
|
10
|
+
* resolved response body so it can be inspected or mutated. Cannot short-circuit.
|
|
11
|
+
*/
|
|
12
|
+
export type MiddlewareResponseHandler = (event: H3Event, response: {
|
|
13
|
+
body?: unknown;
|
|
14
|
+
}) => void | Promise<void>;
|
|
15
|
+
/** A single middleware unit. Either hook is optional. */
|
|
16
|
+
export type Middleware = {
|
|
17
|
+
onRequest?: MiddlewareRequestHandler;
|
|
18
|
+
onBeforeResponse?: MiddlewareResponseHandler;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Compose an ordered array of middleware into a single Vinxi middleware object.
|
|
22
|
+
*
|
|
23
|
+
* `onRequest` hooks run in array order and stop as soon as one returns a
|
|
24
|
+
* `Response` or marks the event handled. `onBeforeResponse` hooks always all
|
|
25
|
+
* run, in array order.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* // app/middleware.ts
|
|
30
|
+
* import { defineMiddleware } from 'solidstep/utils/middleware';
|
|
31
|
+
*
|
|
32
|
+
* export default defineMiddleware([
|
|
33
|
+
* authMiddleware,
|
|
34
|
+
* corsMiddleware,
|
|
35
|
+
* csrfMiddleware,
|
|
36
|
+
* ]);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare const defineMiddleware: (middlewares: Middleware[]) => {
|
|
40
|
+
onRequest?: import("vinxi/http")._RequestMiddleware | import("vinxi/http")._RequestMiddleware[] | undefined;
|
|
41
|
+
onBeforeResponse?: import("vinxi/http")._ResponseMiddleware | import("vinxi/http")._ResponseMiddleware[] | undefined;
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../utils/middleware.ts"],"names":[],"mappings":"AAOA,OAAO,EAA6C,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAErF;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACnC,KAAK,EAAE,OAAO,KACb,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;AAEhD;;;GAGG;AACH,MAAM,MAAM,yBAAyB,GAAG,CACpC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,KAC3B,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,yDAAyD;AACzD,MAAM,MAAM,UAAU,GAAG;IACrB,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,gBAAgB,CAAC,EAAE,yBAAyB,CAAC;CAChD,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,GAAI,aAAa,UAAU,EAAE;;;CAmBpD,CAAC"}
|