@manyducks.co/dolla 2.0.0-alpha.6 → 2.0.0-alpha.61
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 +86 -591
- package/dist/core/context.d.ts +142 -0
- package/dist/core/env.d.ts +3 -0
- package/dist/core/index.d.ts +21 -0
- package/dist/core/logger.d.ts +42 -0
- package/dist/core/logger.test.d.ts +0 -0
- package/dist/core/markup.d.ts +104 -0
- package/dist/core/markup.test.d.ts +0 -0
- package/dist/core/mount.d.ts +15 -0
- package/dist/core/mount.test.d.ts +0 -0
- package/dist/core/nodes/_markup.d.ts +36 -0
- package/dist/core/nodes/dom.d.ts +13 -0
- package/dist/core/nodes/dynamic.d.ts +22 -0
- package/dist/core/nodes/element.d.ts +25 -0
- package/dist/core/nodes/portal.d.ts +18 -0
- package/dist/core/nodes/repeat.d.ts +27 -0
- package/dist/core/nodes/view.d.ts +25 -0
- package/dist/core/ref.d.ts +18 -0
- package/dist/core/ref.test.d.ts +1 -0
- package/dist/core/signals.d.ts +58 -0
- package/dist/core/signals.test.d.ts +1 -0
- package/dist/{views → core/views}/default-crash-view.d.ts +11 -4
- package/dist/core/views/fragment.d.ts +7 -0
- package/dist/fragment-BahD_BJA.js +7 -0
- package/dist/fragment-BahD_BJA.js.map +1 -0
- package/dist/hooks/index.d.ts +64 -0
- package/dist/hooks/index.test.d.ts +1 -0
- package/dist/hooks.js +69 -0
- package/dist/hooks.js.map +1 -0
- package/dist/{modules/http.d.ts → http/index.d.ts} +3 -5
- package/dist/http.js +163 -0
- package/dist/http.js.map +1 -0
- package/dist/i18n/index.d.ts +134 -0
- package/dist/i18n.js +318 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.js +98 -1388
- package/dist/index.js.map +1 -1
- package/dist/jsx-dev-runtime.d.ts +3 -2
- package/dist/jsx-dev-runtime.js +5 -12
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +4 -3
- package/dist/jsx-runtime.js +9 -15
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/logger-Bl496yfY.js +91 -0
- package/dist/logger-Bl496yfY.js.map +1 -0
- package/dist/markup-CX27GJ1M.js +1030 -0
- package/dist/markup-CX27GJ1M.js.map +1 -0
- package/dist/ref-BD79iqlg.js +15 -0
- package/dist/ref-BD79iqlg.js.map +1 -0
- package/dist/router/index.d.ts +2 -0
- package/dist/router/router.d.ts +160 -0
- package/dist/{routing.d.ts → router/router.utils.d.ts} +17 -3
- package/dist/router/router.utils.test.d.ts +1 -0
- package/dist/router-CjCkk4dA.js +543 -0
- package/dist/router-CjCkk4dA.js.map +1 -0
- package/dist/router.js +8 -0
- package/dist/router.js.map +1 -0
- package/dist/signals-gCwiIe5X.js +450 -0
- package/dist/signals-gCwiIe5X.js.map +1 -0
- package/dist/typeChecking-CbltMOUt.js +71 -0
- package/dist/typeChecking-CbltMOUt.js.map +1 -0
- package/dist/typeChecking.d.ts +2 -98
- package/dist/typeChecking.test.d.ts +1 -0
- package/dist/types.d.ts +98 -25
- package/dist/utils.d.ts +20 -3
- package/docs/hooks.md +211 -0
- package/docs/http.md +29 -0
- package/docs/i18n.md +43 -0
- package/docs/index.md +10 -0
- package/docs/markup.md +16 -0
- package/docs/mixins.md +32 -0
- package/docs/ref.md +93 -0
- package/docs/router.md +80 -0
- package/docs/setup.md +31 -0
- package/docs/signals.md +166 -0
- package/docs/state.md +141 -0
- package/docs/stores.md +62 -0
- package/docs/views.md +208 -0
- package/examples/webcomponent/index.html +14 -0
- package/examples/webcomponent/main.js +165 -0
- package/index.d.ts +2 -2
- package/notes/TODO.md +6 -0
- package/notes/atomic.md +452 -0
- package/notes/context-routes.md +61 -0
- package/notes/custom-nodes.md +17 -0
- package/notes/effection-idea.md +34 -0
- package/notes/elimination.md +33 -0
- package/notes/mixins.md +22 -0
- package/notes/molecule.md +35 -0
- package/notes/observable.md +180 -0
- package/notes/readme-scratch.md +45 -7
- package/notes/route-middleware.md +42 -0
- package/notes/scratch.md +353 -6
- package/notes/splitting.md +5 -0
- package/notes/stores.md +79 -0
- package/package.json +31 -12
- package/vite.config.js +6 -11
- package/build.js +0 -34
- package/dist/index.d.ts +0 -21
- package/dist/markup.d.ts +0 -100
- package/dist/modules/dolla.d.ts +0 -111
- package/dist/modules/language.d.ts +0 -41
- package/dist/modules/render.d.ts +0 -17
- package/dist/modules/router.d.ts +0 -152
- package/dist/nodes/cond.d.ts +0 -26
- package/dist/nodes/html.d.ts +0 -31
- package/dist/nodes/observer.d.ts +0 -29
- package/dist/nodes/outlet.d.ts +0 -22
- package/dist/nodes/portal.d.ts +0 -19
- package/dist/nodes/repeat.d.ts +0 -34
- package/dist/nodes/text.d.ts +0 -19
- package/dist/passthrough-CW8Ezjg-.js +0 -1244
- package/dist/passthrough-CW8Ezjg-.js.map +0 -1
- package/dist/state.d.ts +0 -101
- package/dist/view.d.ts +0 -50
- package/dist/views/passthrough.d.ts +0 -5
- package/tests/state.test.js +0 -135
- /package/dist/{routing.test.d.ts → core/context.test.d.ts} +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Context, Logger, type Ref, type Store } from "../core";
|
|
2
|
+
import { type EffectFn, MaybeSignal, type Signal } from "../core/signals";
|
|
3
|
+
/**
|
|
4
|
+
* Returns the Context object of the View, Store or Mixin this hook is called in.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useContext(): Context;
|
|
7
|
+
/**
|
|
8
|
+
* Returns a logger. If a name is passed it will be used as a prefix for all console messages.
|
|
9
|
+
* Otherwise the default name of the context will be used.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useLogger(name?: MaybeSignal<string>): Logger;
|
|
12
|
+
/**
|
|
13
|
+
* Sets the value of the Signal it is bound to.
|
|
14
|
+
*/
|
|
15
|
+
export interface Setter<T> {
|
|
16
|
+
(value: T): void;
|
|
17
|
+
(fn: (current: T) => T): void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates a new read-only Signal and a bound Setter function.
|
|
21
|
+
*/
|
|
22
|
+
export declare function useState<T>(value: T): [Signal<T>, Setter<T>];
|
|
23
|
+
/**
|
|
24
|
+
* Creates a new read-only Signal and a bound Setter function.
|
|
25
|
+
*/
|
|
26
|
+
export declare function useState<T>(): [Signal<T | undefined>, Setter<T | undefined>];
|
|
27
|
+
export declare function useMemo<T>(compute: (current?: T) => T, deps?: Signal<any>[]): Signal<T>;
|
|
28
|
+
export declare function useEffect(fn: EffectFn, deps?: Signal<any>[]): void;
|
|
29
|
+
/**
|
|
30
|
+
* Takes the current state and a dispatched action. Returns a new state based on the action.
|
|
31
|
+
* Typically the body of this function will be a large switch statement.
|
|
32
|
+
*/
|
|
33
|
+
export type ReducerFn<State, Action> = (state: State, action: Action) => State;
|
|
34
|
+
/**
|
|
35
|
+
* Dispatches an action to this reducer, causing the state to update.
|
|
36
|
+
*/
|
|
37
|
+
export type DispatchFn<Action> = (action: Action) => void;
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
*/
|
|
41
|
+
export declare function useReducer<State, Action>(reducer: ReducerFn<State, Action>, initialState: State): [Signal<State>, DispatchFn<Action>];
|
|
42
|
+
/**
|
|
43
|
+
* Uses a previously added Store. Takes the Store function itself and returns the nearest instance.
|
|
44
|
+
*/
|
|
45
|
+
export declare function useStore<T>(store: Store<any, T>): T;
|
|
46
|
+
/**
|
|
47
|
+
* A hybrid Ref which is both a function ref and a React-style object ref with a `current` property.
|
|
48
|
+
* Both the `current` property and the function syntax access the same value.
|
|
49
|
+
*/
|
|
50
|
+
export interface HybridRef<T> extends Ref<T> {
|
|
51
|
+
current: T;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Creates a Ref. Useful for getting references to DOM nodes.
|
|
55
|
+
*/
|
|
56
|
+
export declare function useRef<T>(initialValue?: T): HybridRef<T>;
|
|
57
|
+
/**
|
|
58
|
+
* Calls `callback` when the context is mounted. If `callback` returns a function, that function is called when the context is unmounted.
|
|
59
|
+
*/
|
|
60
|
+
export declare function useMount(callback: () => void | (() => void)): void;
|
|
61
|
+
/**
|
|
62
|
+
* Calls `callback` when the context is unmounted.
|
|
63
|
+
*/
|
|
64
|
+
export declare function useUnmount(callback: () => void): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { $ as u, g as c, u as s, c as a } from "./signals-gCwiIe5X.js";
|
|
2
|
+
import { r as x } from "./ref-BD79iqlg.js";
|
|
3
|
+
function o() {
|
|
4
|
+
const t = a();
|
|
5
|
+
if (!t)
|
|
6
|
+
throw new Error("No context found; hooks can only be called in the body of a View, Store or Mixin.");
|
|
7
|
+
return t;
|
|
8
|
+
}
|
|
9
|
+
function m(t) {
|
|
10
|
+
const e = o();
|
|
11
|
+
return t && e.setName(t), e;
|
|
12
|
+
}
|
|
13
|
+
function l(t) {
|
|
14
|
+
o();
|
|
15
|
+
const e = u(t);
|
|
16
|
+
return [() => e(), e];
|
|
17
|
+
}
|
|
18
|
+
function p(t, e) {
|
|
19
|
+
return o(), e ? u(function() {
|
|
20
|
+
for (const n of e) c(n);
|
|
21
|
+
return s(() => t(this.value));
|
|
22
|
+
}) : u(function() {
|
|
23
|
+
return t(this.value);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function S(t, e) {
|
|
27
|
+
const n = o();
|
|
28
|
+
e ? n.effect(() => {
|
|
29
|
+
for (const r of e) c(r);
|
|
30
|
+
s(t);
|
|
31
|
+
}) : n.effect(t);
|
|
32
|
+
}
|
|
33
|
+
function v(t, e) {
|
|
34
|
+
const [n, r] = l(e);
|
|
35
|
+
return [n, (f) => {
|
|
36
|
+
r((i) => t(i, f));
|
|
37
|
+
}];
|
|
38
|
+
}
|
|
39
|
+
function M(t) {
|
|
40
|
+
return o().getStore(t);
|
|
41
|
+
}
|
|
42
|
+
function b(...t) {
|
|
43
|
+
o();
|
|
44
|
+
const e = x(...t);
|
|
45
|
+
return Object.defineProperty(e, "current", { get: e, set: e }), e;
|
|
46
|
+
}
|
|
47
|
+
function w(t) {
|
|
48
|
+
const e = o();
|
|
49
|
+
e.onMount(() => {
|
|
50
|
+
const n = t();
|
|
51
|
+
n && e.onUnmount(n);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function y(t) {
|
|
55
|
+
o().onUnmount(t);
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
o as useContext,
|
|
59
|
+
S as useEffect,
|
|
60
|
+
m as useLogger,
|
|
61
|
+
p as useMemo,
|
|
62
|
+
w as useMount,
|
|
63
|
+
v as useReducer,
|
|
64
|
+
b as useRef,
|
|
65
|
+
l as useState,
|
|
66
|
+
M as useStore,
|
|
67
|
+
y as useUnmount
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sources":["../src/hooks/index.ts"],"sourcesContent":["import { Context, Logger, ref, type Ref, type Store } from \"../core\";\nimport { $, type EffectFn, get, getCurrentContext, MaybeSignal, type Signal, untracked } from \"../core/signals\";\n\n/**\n * Returns the Context object of the View, Store or Mixin this hook is called in.\n */\nexport function useContext(): Context {\n const context = getCurrentContext();\n if (!context) {\n throw new Error(`No context found; hooks can only be called in the body of a View, Store or Mixin.`);\n }\n return context;\n}\n\n/**\n * Returns a logger. If a name is passed it will be used as a prefix for all console messages.\n * Otherwise the default name of the context will be used.\n */\nexport function useLogger(name?: MaybeSignal<string>): Logger {\n const context = useContext();\n if (name) context.setName(name);\n return context;\n}\n\n/**\n * Sets the value of the Signal it is bound to.\n */\nexport interface Setter<T> {\n (value: T): void;\n (fn: (current: T) => T): void;\n}\n\n/**\n * Creates a new read-only Signal and a bound Setter function.\n */\nexport function useState<T>(value: T): [Signal<T>, Setter<T>];\n\n/**\n * Creates a new read-only Signal and a bound Setter function.\n */\nexport function useState<T>(): [Signal<T | undefined>, Setter<T | undefined>];\n\nexport function useState<T>(value?: T): [Signal<T>, Setter<T>] {\n useContext(); // assert that we're in a valid context\n const $value = $(value);\n return [() => $value() as T, $value];\n}\n\nexport function useMemo<T>(compute: (current?: T) => T, deps?: Signal<any>[]): Signal<T> {\n useContext(); // assert that we're in a valid context\n if (deps) {\n return $(function () {\n // Track deps and run `compute` untracked.\n for (const dep of deps) get(dep);\n return untracked(() => compute(this.value));\n });\n } else {\n return $(function () {\n return compute(this.value);\n });\n }\n}\n\nexport function useEffect(fn: EffectFn, deps?: Signal<any>[]): void {\n const context = useContext();\n if (deps) {\n context.effect(() => {\n // Track deps and run `fn` untracked.\n for (const dep of deps) get(dep);\n untracked(fn);\n });\n } else {\n context.effect(fn);\n }\n}\n\n// TODO: What would layout effect even mean in dolla?\n// export function useLayoutEffect() {}\n\n/**\n * Takes the current state and a dispatched action. Returns a new state based on the action.\n * Typically the body of this function will be a large switch statement.\n */\nexport type ReducerFn<State, Action> = (state: State, action: Action) => State;\n\n/**\n * Dispatches an action to this reducer, causing the state to update.\n */\nexport type DispatchFn<Action> = (action: Action) => void;\n\n/**\n *\n */\nexport function useReducer<State, Action>(\n reducer: ReducerFn<State, Action>,\n initialState: State,\n): [Signal<State>, DispatchFn<Action>] {\n const [state, setState] = useState(initialState);\n const dispatch = (action: Action) => {\n setState((current) => reducer(current, action));\n };\n return [state, dispatch];\n}\n\n/**\n * Uses a previously added Store. Takes the Store function itself and returns the nearest instance.\n */\nexport function useStore<T>(store: Store<any, T>): T {\n const context = useContext();\n return context.getStore(store);\n}\n\n/**\n * A hybrid Ref which is both a function ref and a React-style object ref with a `current` property.\n * Both the `current` property and the function syntax access the same value.\n */\nexport interface HybridRef<T> extends Ref<T> {\n current: T;\n}\n\n/**\n * Creates a Ref. Useful for getting references to DOM nodes.\n */\nexport function useRef<T>(initialValue?: T): HybridRef<T>;\n\nexport function useRef<T>(...value: [T]): HybridRef<T> {\n useContext(); // assert that we're in a valid context\n const valueRef = ref(...value);\n Object.defineProperty(valueRef, \"current\", { get: valueRef, set: valueRef });\n return valueRef as HybridRef<T>;\n}\n\n/**\n * Calls `callback` when the context is mounted. If `callback` returns a function, that function is called when the context is unmounted.\n */\nexport function useMount(callback: () => void | (() => void)): void {\n const context = useContext();\n context.onMount(() => {\n const result = callback();\n if (result) context.onUnmount(result);\n });\n}\n\n/**\n * Calls `callback` when the context is unmounted.\n */\nexport function useUnmount(callback: () => void): void {\n const context = useContext();\n context.onUnmount(callback);\n}\n"],"names":["useContext","context","getCurrentContext","useLogger","name","useState","value","$value","$","useMemo","compute","deps","dep","get","untracked","useEffect","fn","useReducer","reducer","initialState","state","setState","action","current","useStore","store","useRef","valueRef","ref","useMount","callback","result","useUnmount"],"mappings":";;AAMO,SAASA,IAAsB;AACpC,QAAMC,IAAUC,EAAkB;AAClC,MAAI,CAACD;AACG,UAAA,IAAI,MAAM,mFAAmF;AAE9F,SAAAA;AACT;AAMO,SAASE,EAAUC,GAAoC;AAC5D,QAAMH,IAAUD,EAAW;AACvB,SAAAI,KAAcH,EAAA,QAAQG,CAAI,GACvBH;AACT;AAoBO,SAASI,EAAYC,GAAmC;AAClD,EAAAN,EAAA;AACL,QAAAO,IAASC,EAAEF,CAAK;AACtB,SAAO,CAAC,MAAMC,EAAO,GAAQA,CAAM;AACrC;AAEgB,SAAAE,EAAWC,GAA6BC,GAAiC;AAEvF,SADWX,EAAA,GACPW,IACKH,EAAE,WAAY;AAER,eAAAI,KAAOD,EAAM,CAAAE,EAAID,CAAG;AAC/B,WAAOE,EAAU,MAAMJ,EAAQ,KAAK,KAAK,CAAC;AAAA,EAAA,CAC3C,IAEMF,EAAE,WAAY;AACZ,WAAAE,EAAQ,KAAK,KAAK;AAAA,EAAA,CAC1B;AAEL;AAEgB,SAAAK,EAAUC,GAAcL,GAA4B;AAClE,QAAMV,IAAUD,EAAW;AAC3B,EAAIW,IACFV,EAAQ,OAAO,MAAM;AAER,eAAAW,KAAOD,EAAM,CAAAE,EAAID,CAAG;AAC/B,IAAAE,EAAUE,CAAE;AAAA,EAAA,CACb,IAEDf,EAAQ,OAAOe,CAAE;AAErB;AAmBgB,SAAAC,EACdC,GACAC,GACqC;AACrC,QAAM,CAACC,GAAOC,CAAQ,IAAIhB,EAASc,CAAY;AAIxC,SAAA,CAACC,GAHS,CAACE,MAAmB;AACnC,IAAAD,EAAS,CAACE,MAAYL,EAAQK,GAASD,CAAM,CAAC;AAAA,EAChD,CACuB;AACzB;AAKO,SAASE,EAAYC,GAAyB;AAE5C,SADSzB,EAAW,EACZ,SAASyB,CAAK;AAC/B;AAeO,SAASC,KAAapB,GAA0B;AAC1C,EAAAN,EAAA;AACL,QAAA2B,IAAWC,EAAI,GAAGtB,CAAK;AACtB,gBAAA,eAAeqB,GAAU,WAAW,EAAE,KAAKA,GAAU,KAAKA,GAAU,GACpEA;AACT;AAKO,SAASE,EAASC,GAA2C;AAClE,QAAM7B,IAAUD,EAAW;AAC3B,EAAAC,EAAQ,QAAQ,MAAM;AACpB,UAAM8B,IAASD,EAAS;AACpB,IAAAC,KAAgB9B,EAAA,UAAU8B,CAAM;AAAA,EAAA,CACrC;AACH;AAKO,SAASC,EAAWF,GAA4B;AAErD,EADgB9B,EAAW,EACnB,UAAU8B,CAAQ;AAC5B;"}
|
|
@@ -37,18 +37,16 @@ export interface RequestOptions<ReqBody> {
|
|
|
37
37
|
}
|
|
38
38
|
export interface HTTPRequest<Body> {
|
|
39
39
|
method: string;
|
|
40
|
-
|
|
41
|
-
readonly sameOrigin: boolean;
|
|
40
|
+
url: URL;
|
|
42
41
|
headers: Headers;
|
|
43
|
-
query: URLSearchParams;
|
|
44
42
|
body: Body;
|
|
45
43
|
}
|
|
46
44
|
export interface HTTPResponse<Body> {
|
|
47
45
|
method: string;
|
|
48
|
-
|
|
46
|
+
url: URL;
|
|
47
|
+
headers: Headers;
|
|
49
48
|
status: number;
|
|
50
49
|
statusText: string;
|
|
51
|
-
headers: Record<string, string>;
|
|
52
50
|
body: Body;
|
|
53
51
|
}
|
|
54
52
|
export declare class HTTPResponseError extends Error {
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
var b = Object.defineProperty;
|
|
2
|
+
var f = (r) => {
|
|
3
|
+
throw TypeError(r);
|
|
4
|
+
};
|
|
5
|
+
var g = (r, e, t) => e in r ? b(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
|
|
6
|
+
var a = (r, e, t) => g(r, typeof e != "symbol" ? e + "" : e, t), m = (r, e, t) => e.has(r) || f("Cannot " + t);
|
|
7
|
+
var d = (r, e, t) => (m(r, e, "read from private field"), t ? t.call(r) : e.get(r)), c = (r, e, t) => e.has(r) ? f("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(r) : e.set(r, t);
|
|
8
|
+
var o = (r, e, t) => (m(r, e, "access private method"), t);
|
|
9
|
+
import { i as w } from "./typeChecking-CbltMOUt.js";
|
|
10
|
+
var l, p, i, h;
|
|
11
|
+
class O {
|
|
12
|
+
constructor() {
|
|
13
|
+
c(this, i);
|
|
14
|
+
c(this, l, []);
|
|
15
|
+
c(this, p, S());
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Adds a new middleware that will apply to subsequent requests.
|
|
19
|
+
* Returns a function to remove this middleware.
|
|
20
|
+
*
|
|
21
|
+
* @param middleware - A middleware function that will intercept requests.
|
|
22
|
+
*/
|
|
23
|
+
use(e) {
|
|
24
|
+
return d(this, l).push(e), () => {
|
|
25
|
+
d(this, l).splice(d(this, l).indexOf(e), 1);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
async get(e, t) {
|
|
29
|
+
return o(this, i, h).call(this, "get", e, t);
|
|
30
|
+
}
|
|
31
|
+
async put(e, t) {
|
|
32
|
+
return o(this, i, h).call(this, "put", e, t);
|
|
33
|
+
}
|
|
34
|
+
async patch(e, t) {
|
|
35
|
+
return o(this, i, h).call(this, "patch", e, t);
|
|
36
|
+
}
|
|
37
|
+
async post(e, t) {
|
|
38
|
+
return o(this, i, h).call(this, "post", e, t);
|
|
39
|
+
}
|
|
40
|
+
async delete(e, t) {
|
|
41
|
+
return o(this, i, h).call(this, "delete", e, t);
|
|
42
|
+
}
|
|
43
|
+
async head(e, t) {
|
|
44
|
+
return o(this, i, h).call(this, "head", e, t);
|
|
45
|
+
}
|
|
46
|
+
async options(e, t) {
|
|
47
|
+
return o(this, i, h).call(this, "options", e, t);
|
|
48
|
+
}
|
|
49
|
+
async trace(e, t) {
|
|
50
|
+
return o(this, i, h).call(this, "trace", e, t);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
l = new WeakMap(), p = new WeakMap(), i = new WeakSet(), h = async function(e, t, s) {
|
|
54
|
+
return new x({
|
|
55
|
+
...s,
|
|
56
|
+
method: e,
|
|
57
|
+
uri: t,
|
|
58
|
+
middleware: d(this, l),
|
|
59
|
+
fetch: d(this, p)
|
|
60
|
+
}).fetch();
|
|
61
|
+
};
|
|
62
|
+
function S() {
|
|
63
|
+
if (typeof window < "u" && window.fetch)
|
|
64
|
+
return window.fetch.bind(window);
|
|
65
|
+
if (typeof global < "u" && global.fetch)
|
|
66
|
+
return global.fetch.bind(global);
|
|
67
|
+
throw new Error("Running in neither browser nor node. Please run this app in one of the supported environments.");
|
|
68
|
+
}
|
|
69
|
+
class P extends Error {
|
|
70
|
+
constructor(t) {
|
|
71
|
+
const { status: s, statusText: n, method: u, url: y } = t, _ = `${s} ${n}: Request failed (${u.toUpperCase()} ${y.toString()})`;
|
|
72
|
+
super(_);
|
|
73
|
+
a(this, "response");
|
|
74
|
+
this.response = t;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
class R {
|
|
78
|
+
constructor(e) {
|
|
79
|
+
a(this, "method");
|
|
80
|
+
a(this, "url");
|
|
81
|
+
a(this, "headers", new Headers());
|
|
82
|
+
a(this, "body");
|
|
83
|
+
this.method = e.method, this.body = e.body, e.uri.startsWith("http") ? this.url = new URL(e.uri) : this.url = new URL(e.uri, window.location.origin), this._applyHeaders(e.headers), this._applyQueryParams(e.query);
|
|
84
|
+
}
|
|
85
|
+
get isSameOrigin() {
|
|
86
|
+
return this.url.origin === window.location.origin;
|
|
87
|
+
}
|
|
88
|
+
_applyHeaders(e) {
|
|
89
|
+
if (e != null)
|
|
90
|
+
if (e instanceof Map || e instanceof Headers)
|
|
91
|
+
e.forEach((t, s) => {
|
|
92
|
+
this.headers.set(s, t);
|
|
93
|
+
});
|
|
94
|
+
else if (w(e))
|
|
95
|
+
for (const t in e) {
|
|
96
|
+
const s = e[t];
|
|
97
|
+
s instanceof Date ? this.headers.set(t, s.toISOString()) : s != null && this.headers.set(t, String(s));
|
|
98
|
+
}
|
|
99
|
+
else
|
|
100
|
+
throw new TypeError(`Unknown headers type. Got: ${e}`);
|
|
101
|
+
}
|
|
102
|
+
_applyQueryParams(e) {
|
|
103
|
+
if (e != null)
|
|
104
|
+
if (e instanceof Map || e instanceof URLSearchParams)
|
|
105
|
+
e.forEach((t, s) => {
|
|
106
|
+
this.url.searchParams.set(s, t);
|
|
107
|
+
});
|
|
108
|
+
else if (w(e))
|
|
109
|
+
for (const t in e) {
|
|
110
|
+
const s = e[t];
|
|
111
|
+
s instanceof Date ? this.url.searchParams.set(t, s.toISOString()) : s != null && this.url.searchParams.set(t, String(s));
|
|
112
|
+
}
|
|
113
|
+
else
|
|
114
|
+
throw new TypeError(`Unknown query params type. Got: ${e}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
class x {
|
|
118
|
+
constructor(e) {
|
|
119
|
+
a(this, "_middleware");
|
|
120
|
+
a(this, "_fetch");
|
|
121
|
+
a(this, "_request");
|
|
122
|
+
a(this, "_response");
|
|
123
|
+
this._middleware = e.middleware, this._fetch = e.fetch, this._request = new R(e);
|
|
124
|
+
}
|
|
125
|
+
async fetch() {
|
|
126
|
+
if (this._middleware.length > 0) {
|
|
127
|
+
const e = (t = 0) => {
|
|
128
|
+
const s = this._middleware[t], n = this._middleware[t + 1] ? e(t + 1) : this._handler.bind(this);
|
|
129
|
+
return async () => s(this._request, async () => (await n(), this._response));
|
|
130
|
+
};
|
|
131
|
+
await e()();
|
|
132
|
+
} else
|
|
133
|
+
await this._handler();
|
|
134
|
+
if (this._response.status < 200 || this._response.status >= 400)
|
|
135
|
+
throw new P(this._response);
|
|
136
|
+
return this._response;
|
|
137
|
+
}
|
|
138
|
+
// This is the function that performs the actual request after the final middleware.
|
|
139
|
+
async _handler() {
|
|
140
|
+
let e;
|
|
141
|
+
const t = this._request;
|
|
142
|
+
!t.headers.has("content-type") && w(t.body) ? (t.headers.set("content-type", "application/json"), e = JSON.stringify(t.body)) : e = t.body;
|
|
143
|
+
const s = await this._fetch(t.url.toString(), {
|
|
144
|
+
method: t.method,
|
|
145
|
+
headers: t.headers,
|
|
146
|
+
body: e
|
|
147
|
+
}), n = s.headers.get("content-type");
|
|
148
|
+
let u;
|
|
149
|
+
n != null && n.includes("application/json") ? u = await s.json() : n != null && n.includes("application/x-www-form-urlencoded") ? u = await s.formData() : u = await s.text(), this._response = {
|
|
150
|
+
method: t.method,
|
|
151
|
+
url: t.url,
|
|
152
|
+
status: s.status,
|
|
153
|
+
statusText: s.statusText,
|
|
154
|
+
headers: s.headers,
|
|
155
|
+
body: u
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export {
|
|
160
|
+
O as HTTP,
|
|
161
|
+
P as HTTPResponseError
|
|
162
|
+
};
|
|
163
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sources":["../src/http/index.ts"],"sourcesContent":["import { isObject } from \"../typeChecking.js\";\n\n/**\n * A simple HTTP client with middleware support. Middleware applies to all requests made through this store,\n * so it's the perfect way to handle things like auth headers and permission checks for API calls.\n */\nexport class HTTP {\n #middleware: HTTPMiddleware[] = [];\n #fetch = getDefaultFetch();\n\n /**\n * Adds a new middleware that will apply to subsequent requests.\n * Returns a function to remove this middleware.\n *\n * @param middleware - A middleware function that will intercept requests.\n */\n use(fn: HTTPMiddleware) {\n this.#middleware.push(fn);\n\n // Call returned function to remove this middleware for subsequent requests.\n return () => {\n this.#middleware.splice(this.#middleware.indexOf(fn), 1);\n };\n }\n\n async get<ResBody = unknown>(uri: string, options?: RequestOptions<never>) {\n return this.#request<ResBody, never>(\"get\", uri, options);\n }\n\n async put<ResBody = unknown, ReqBody = unknown>(uri: string, options?: RequestOptions<ReqBody>) {\n return this.#request<ResBody, ReqBody>(\"put\", uri, options);\n }\n\n async patch<ResBody = unknown, ReqBody = unknown>(uri: string, options?: RequestOptions<ReqBody>) {\n return this.#request<ResBody, ReqBody>(\"patch\", uri, options);\n }\n\n async post<ResBody = unknown, ReqBody = unknown>(uri: string, options?: RequestOptions<ReqBody>) {\n return this.#request<ResBody, ReqBody>(\"post\", uri, options);\n }\n\n async delete<ResBody = unknown>(uri: string, options?: RequestOptions<never>) {\n return this.#request<ResBody, never>(\"delete\", uri, options);\n }\n\n async head<ResBody = unknown, ReqBody = unknown>(uri: string, options?: RequestOptions<ReqBody>) {\n return this.#request<ResBody, ReqBody>(\"head\", uri, options);\n }\n\n async options<ResBody = unknown, ReqBody = unknown>(uri: string, options?: RequestOptions<ReqBody>) {\n return this.#request<ResBody, ReqBody>(\"options\", uri, options);\n }\n\n async trace<ResBody = unknown, ReqBody = unknown>(uri: string, options?: RequestOptions<ReqBody>) {\n return this.#request<ResBody, ReqBody>(\"trace\", uri, options);\n }\n\n async #request<ResBody, ReqBody>(method: string, uri: string, options?: RequestOptions<any>) {\n const runner = new Runner<ResBody, ReqBody>({\n ...options,\n method,\n uri,\n middleware: this.#middleware,\n fetch: this.#fetch,\n });\n return runner.fetch();\n }\n}\n\nfunction getDefaultFetch(): typeof window.fetch {\n if (typeof window !== \"undefined\" && window.fetch) {\n return window.fetch.bind(window);\n }\n\n if (typeof global !== \"undefined\" && global.fetch) {\n return global.fetch.bind(global);\n }\n\n throw new Error(\"Running in neither browser nor node. Please run this app in one of the supported environments.\");\n}\n\n/*====================*\\\n|| Request ||\n\\*====================*/\n\nexport type HTTPMiddleware = (\n request: HTTPRequest<unknown>,\n next: () => Promise<HTTPResponse<unknown>>,\n) => void | Promise<void>;\n\nexport interface RequestOptions<ReqBody> {\n /**\n * Body to send with the request.\n */\n body?: ReqBody;\n\n /**\n * Headers to send with the request.\n */\n headers?: Record<string, any> | Headers;\n\n /**\n * Query params to interpolate into the URL.\n */\n query?: Record<string, any> | URLSearchParams;\n}\n\nexport interface HTTPRequest<Body> {\n method: string;\n url: URL;\n headers: Headers;\n body: Body;\n}\n\nexport interface HTTPResponse<Body> {\n method: string;\n url: URL;\n headers: Headers;\n status: number;\n statusText: string;\n body: Body;\n}\n\ninterface MakeRequestConfig<ReqBody> extends RequestOptions<ReqBody> {\n method: string;\n uri: string;\n middleware: HTTPMiddleware[];\n fetch: typeof window.fetch;\n}\n\nexport class HTTPResponseError extends Error {\n response;\n\n constructor(response: HTTPResponse<any>) {\n const { status, statusText, method, url } = response;\n const message = `${status} ${statusText}: Request failed (${method.toUpperCase()} ${url.toString()})`;\n\n super(message);\n\n this.response = response;\n }\n}\n\nclass Request<ReqBody> implements HTTPRequest<ReqBody> {\n method: string;\n url: URL;\n headers = new Headers();\n body!: ReqBody;\n\n get isSameOrigin() {\n return this.url.origin === window.location.origin;\n }\n\n constructor(config: MakeRequestConfig<ReqBody>) {\n this.method = config.method;\n this.body = config.body!;\n if (config.uri.startsWith(\"http\")) {\n this.url = new URL(config.uri);\n } else {\n this.url = new URL(config.uri, window.location.origin);\n }\n\n this._applyHeaders(config.headers);\n this._applyQueryParams(config.query);\n }\n\n private _applyHeaders(headers: any) {\n if (headers == null) return;\n\n if (headers instanceof Map || headers instanceof Headers) {\n headers.forEach((value, key) => {\n this.headers.set(key, value);\n });\n } else if (isObject(headers)) {\n for (const name in headers) {\n const value = headers[name];\n if (value instanceof Date) {\n this.headers.set(name, value.toISOString());\n } else if (value != null) {\n this.headers.set(name, String(value));\n }\n }\n } else {\n throw new TypeError(`Unknown headers type. Got: ${headers}`);\n }\n }\n\n private _applyQueryParams(query: any) {\n if (query == null) return;\n\n if (query instanceof Map || query instanceof URLSearchParams) {\n query.forEach((value, key) => {\n this.url.searchParams.set(key, value);\n });\n } else if (isObject(query)) {\n for (const name in query) {\n const value = query[name];\n if (value instanceof Date) {\n this.url.searchParams.set(name, value.toISOString());\n } else if (value != null) {\n this.url.searchParams.set(name, String(value));\n }\n }\n } else {\n throw new TypeError(`Unknown query params type. Got: ${query}`);\n }\n }\n}\n\nclass Runner<ResBody, ReqBody> {\n private _middleware;\n private _fetch;\n\n private _request: Request<ReqBody>;\n private _response?: HTTPResponse<ResBody>;\n\n constructor(config: MakeRequestConfig<ReqBody>) {\n this._middleware = config.middleware;\n this._fetch = config.fetch;\n\n this._request = new Request(config);\n }\n\n async fetch() {\n if (this._middleware.length > 0) {\n const mount = (index = 0) => {\n const current = this._middleware[index];\n const next = this._middleware[index + 1] ? mount(index + 1) : this._handler.bind(this);\n\n return async () =>\n current(this._request, async () => {\n await next();\n return this._response!;\n });\n };\n\n await mount()();\n } else {\n await this._handler();\n }\n\n if (this._response!.status < 200 || this._response!.status >= 400) {\n throw new HTTPResponseError(this._response!);\n }\n\n return this._response!;\n }\n\n // This is the function that performs the actual request after the final middleware.\n private async _handler() {\n let reqBody: BodyInit;\n\n const req = this._request;\n\n if (!req.headers.has(\"content-type\") && isObject(req.body)) {\n // Auto-detect JSON bodies and encode as a string with correct headers.\n req.headers.set(\"content-type\", \"application/json\");\n reqBody = JSON.stringify(req.body);\n } else {\n reqBody = req.body as BodyInit;\n }\n\n const fetched = await this._fetch(req.url.toString(), {\n method: req.method,\n headers: req.headers,\n body: reqBody,\n });\n\n // Auto-parse response body based on content-type header\n const contentType = fetched.headers.get(\"content-type\");\n\n let body: ResBody;\n\n if (contentType?.includes(\"application/json\")) {\n body = await fetched.json();\n } else if (contentType?.includes(\"application/x-www-form-urlencoded\")) {\n body = (await fetched.formData()) as ResBody;\n } else {\n body = (await fetched.text()) as ResBody;\n }\n\n this._response = {\n method: req.method,\n url: req.url,\n status: fetched.status,\n statusText: fetched.statusText,\n headers: fetched.headers,\n body,\n };\n }\n}\n"],"names":["HTTP","__privateAdd","_HTTP_instances","_middleware","_fetch","getDefaultFetch","fn","__privateGet","uri","options","__privateMethod","request_fn","method","Runner","HTTPResponseError","response","status","statusText","url","message","__publicField","Request","config","headers","value","key","isObject","name","query","mount","index","current","next","reqBody","req","fetched","contentType","body"],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { type MaybeSignal, type Signal } from "../core/signals.js";
|
|
2
|
+
/**
|
|
3
|
+
* A JSON object of translated strings. Values can be string templates or nested objects.
|
|
4
|
+
*/
|
|
5
|
+
interface LocalizedStrings extends Record<string, string | LocalizedStrings> {
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A formatter to be applied to a variable.
|
|
9
|
+
*/
|
|
10
|
+
type Format = {
|
|
11
|
+
name: string;
|
|
12
|
+
options: Record<string, any>;
|
|
13
|
+
};
|
|
14
|
+
export interface TranslationConfig {
|
|
15
|
+
/**
|
|
16
|
+
* Name of the locale this translation is for (BCP 47 locale names recommended).
|
|
17
|
+
*/
|
|
18
|
+
locale: string;
|
|
19
|
+
/**
|
|
20
|
+
* An object with translated strings for this language.
|
|
21
|
+
*/
|
|
22
|
+
strings?: LocalizedStrings;
|
|
23
|
+
/**
|
|
24
|
+
* A callback function that returns a Promise that resolves to the translation object for this language.
|
|
25
|
+
*/
|
|
26
|
+
fetch?: () => Promise<LocalizedStrings>;
|
|
27
|
+
/**
|
|
28
|
+
* Path to a JSON file with translated strings for this language.
|
|
29
|
+
*/
|
|
30
|
+
path?: string;
|
|
31
|
+
}
|
|
32
|
+
export type I18nSetupOptions = {
|
|
33
|
+
/**
|
|
34
|
+
* Default locale to load on startup
|
|
35
|
+
*/
|
|
36
|
+
locale?: string | null;
|
|
37
|
+
translations: TranslationConfig[];
|
|
38
|
+
};
|
|
39
|
+
export type TOptions = {
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
*/
|
|
43
|
+
count?: MaybeSignal<number>;
|
|
44
|
+
/**
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
context?: MaybeSignal<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Override formats specified in the template with the ones in the array for each named variable.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* t("example_key", {
|
|
53
|
+
* count: 5,
|
|
54
|
+
* formatOverrides: {
|
|
55
|
+
* count: [ { name: "datetime", options: { style: "currency", currency: "JPY" } } ]
|
|
56
|
+
* }
|
|
57
|
+
* });
|
|
58
|
+
*/
|
|
59
|
+
formatOverrides?: MaybeSignal<Record<string, Record<string, Format[]>>>;
|
|
60
|
+
[value: string]: MaybeSignal<any>;
|
|
61
|
+
};
|
|
62
|
+
export type Formatter = (locale: string, value: unknown, options: Record<string, any>) => string;
|
|
63
|
+
/**
|
|
64
|
+
* Dolla's I(nternationalizatio)n module. Manages language translations and locale-based formatting.
|
|
65
|
+
*/
|
|
66
|
+
declare class I18n {
|
|
67
|
+
#private;
|
|
68
|
+
readonly $locale: Signal<string>;
|
|
69
|
+
constructor();
|
|
70
|
+
get locales(): string[];
|
|
71
|
+
setup(options: I18nSetupOptions): Promise<void>;
|
|
72
|
+
setLocale(name: string): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Returns a State containing the value at `key`.
|
|
75
|
+
|
|
76
|
+
* @param selector - Key to the translated value.
|
|
77
|
+
* @param options - A map of `{{placeholder}}` names and the values to replace them with.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* const $value = t("your.key.here", { count: 5 });
|
|
81
|
+
*/
|
|
82
|
+
t(selector: string, options?: TOptions): Signal<string>;
|
|
83
|
+
/**
|
|
84
|
+
* Add a custom format callback.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* Dolla.i18n.addFormat("uppercase", (locale, value, options) => {
|
|
88
|
+
* return value.toUpperCase();
|
|
89
|
+
* });
|
|
90
|
+
*
|
|
91
|
+
* {
|
|
92
|
+
* "greeting": "Hello, {{name|uppercase}}!"
|
|
93
|
+
* }
|
|
94
|
+
*
|
|
95
|
+
* t("greeting", {name: "world"}); // State<"Hello, WORLD!">
|
|
96
|
+
*/
|
|
97
|
+
addFormat(name: string, callback: (locale: string, value: unknown, options: Record<string, any>) => string): void;
|
|
98
|
+
/**
|
|
99
|
+
* Creates an `Intl.Collator` configured for the current locale.
|
|
100
|
+
* NOTE: The locale is tracked if called within a signal tracking context.
|
|
101
|
+
*
|
|
102
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator#options
|
|
103
|
+
*/
|
|
104
|
+
collator(options?: Intl.CollatorOptions): Intl.Collator;
|
|
105
|
+
/**
|
|
106
|
+
* Formats a number for the current locale. Uses `Intl.NumberFormat` under the hood.
|
|
107
|
+
*
|
|
108
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options
|
|
109
|
+
*/
|
|
110
|
+
number(count: MaybeSignal<number | bigint>, options?: Intl.NumberFormatOptions): Signal<string>;
|
|
111
|
+
/**
|
|
112
|
+
* Formats a date for the current locale. Uses `Intl.DateTimeFormat` under the hood.
|
|
113
|
+
*
|
|
114
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* const date = new Date();
|
|
118
|
+
* const $formatted = Dolla.i18n.dateTime(date, { dateFormat: "short" });
|
|
119
|
+
*/
|
|
120
|
+
dateTime(date?: MaybeSignal<string | number | Date | undefined>, options?: Intl.DateTimeFormatOptions): Signal<string>;
|
|
121
|
+
/**
|
|
122
|
+
* Formats a list for the current locale. Uses `Intl.ListFormat` under the hood.
|
|
123
|
+
*
|
|
124
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* const list = new Date();
|
|
128
|
+
* const $formatted = Dolla.i18n.list(list, { });
|
|
129
|
+
*/
|
|
130
|
+
list(list: MaybeSignal<Iterable<string>>, options?: Intl.ListFormatOptions): Signal<string>;
|
|
131
|
+
}
|
|
132
|
+
export declare const i18n: I18n;
|
|
133
|
+
export declare const t: (selector: string, options?: TOptions) => Signal<string>;
|
|
134
|
+
export {};
|