@fragno-dev/core 0.1.10 → 0.2.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/.turbo/turbo-build.log +139 -131
- package/CHANGELOG.md +63 -0
- package/dist/api/api.d.ts +23 -5
- package/dist/api/api.d.ts.map +1 -1
- package/dist/api/api.js.map +1 -1
- package/dist/api/fragment-definition-builder.d.ts +17 -7
- package/dist/api/fragment-definition-builder.d.ts.map +1 -1
- package/dist/api/fragment-definition-builder.js +3 -2
- package/dist/api/fragment-definition-builder.js.map +1 -1
- package/dist/api/fragment-instantiator.d.ts +129 -32
- package/dist/api/fragment-instantiator.d.ts.map +1 -1
- package/dist/api/fragment-instantiator.js +232 -50
- package/dist/api/fragment-instantiator.js.map +1 -1
- package/dist/api/request-input-context.d.ts +57 -1
- package/dist/api/request-input-context.d.ts.map +1 -1
- package/dist/api/request-input-context.js +67 -0
- package/dist/api/request-input-context.js.map +1 -1
- package/dist/api/request-middleware.d.ts +1 -1
- package/dist/api/request-middleware.d.ts.map +1 -1
- package/dist/api/request-middleware.js.map +1 -1
- package/dist/api/route.d.ts +7 -7
- package/dist/api/route.d.ts.map +1 -1
- package/dist/api/route.js.map +1 -1
- package/dist/client/client.d.ts +4 -3
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +103 -7
- package/dist/client/client.js.map +1 -1
- package/dist/client/vue.d.ts +7 -3
- package/dist/client/vue.d.ts.map +1 -1
- package/dist/client/vue.js +16 -1
- package/dist/client/vue.js.map +1 -1
- package/dist/internal/trace-context.d.ts +23 -0
- package/dist/internal/trace-context.d.ts.map +1 -0
- package/dist/internal/trace-context.js +14 -0
- package/dist/internal/trace-context.js.map +1 -0
- package/dist/mod-client.d.ts +5 -27
- package/dist/mod-client.d.ts.map +1 -1
- package/dist/mod-client.js +50 -13
- package/dist/mod-client.js.map +1 -1
- package/dist/mod.d.ts +4 -3
- package/dist/mod.js +2 -1
- package/dist/runtime.d.ts +15 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +33 -0
- package/dist/runtime.js.map +1 -0
- package/dist/test/test.d.ts +2 -2
- package/dist/test/test.d.ts.map +1 -1
- package/dist/test/test.js.map +1 -1
- package/package.json +31 -18
- package/src/api/api.ts +24 -0
- package/src/api/fragment-definition-builder.ts +36 -17
- package/src/api/fragment-instantiator.test.ts +429 -1
- package/src/api/fragment-instantiator.ts +572 -58
- package/src/api/internal/path-runtime.test.ts +7 -0
- package/src/api/request-input-context.test.ts +152 -0
- package/src/api/request-input-context.ts +85 -0
- package/src/api/request-middleware.test.ts +47 -1
- package/src/api/request-middleware.ts +1 -1
- package/src/api/route.ts +7 -2
- package/src/client/client.test.ts +195 -0
- package/src/client/client.ts +185 -10
- package/src/client/vue.test.ts +253 -3
- package/src/client/vue.ts +44 -1
- package/src/internal/trace-context.ts +35 -0
- package/src/mod-client.ts +89 -9
- package/src/mod.ts +7 -1
- package/src/runtime.ts +48 -0
- package/src/test/test.ts +13 -4
- package/tsdown.config.ts +1 -0
package/dist/client/vue.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isReadableAtom } from "../util/nanostores.js";
|
|
2
|
+
import { isGetHook, isMutatorHook, isStore } from "./client.js";
|
|
2
3
|
import { atom } from "nanostores";
|
|
3
4
|
import { computed as computed$1, getCurrentScope, isRef, onScopeDispose, ref, shallowRef, watch } from "vue";
|
|
4
5
|
|
|
@@ -80,6 +81,19 @@ function createVueMutator(hook) {
|
|
|
80
81
|
};
|
|
81
82
|
};
|
|
82
83
|
}
|
|
84
|
+
function createVueStore(hook) {
|
|
85
|
+
if (isReadableAtom(hook.obj)) return (() => useStore(hook.obj).value);
|
|
86
|
+
return (() => {
|
|
87
|
+
const result = {};
|
|
88
|
+
for (const key in hook.obj) {
|
|
89
|
+
if (!Object.prototype.hasOwnProperty.call(hook.obj, key)) continue;
|
|
90
|
+
const value = hook.obj[key];
|
|
91
|
+
if (isReadableAtom(value)) result[key] = useStore(value).value;
|
|
92
|
+
else result[key] = value;
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
83
97
|
function useFragno(clientObj) {
|
|
84
98
|
const result = {};
|
|
85
99
|
for (const key in clientObj) {
|
|
@@ -87,6 +101,7 @@ function useFragno(clientObj) {
|
|
|
87
101
|
const hook = clientObj[key];
|
|
88
102
|
if (isGetHook(hook)) result[key] = createVueHook(hook);
|
|
89
103
|
else if (isMutatorHook(hook)) result[key] = createVueMutator(hook);
|
|
104
|
+
else if (isStore(hook)) result[key] = createVueStore(hook);
|
|
90
105
|
else result[key] = hook;
|
|
91
106
|
}
|
|
92
107
|
return result;
|
package/dist/client/vue.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vue.js","names":["ref","pathParams: Record<string, string | ReadableAtom<string>>","queryParams: Record<string, string | ReadableAtom<string>>","computed"],"sources":["../../src/client/vue.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { atom, type ReadableAtom, type Store, type StoreValue } from \"nanostores\";\nimport type { DeepReadonly, Ref, ShallowRef, UnwrapNestedRefs } from \"vue\";\nimport { computed, getCurrentScope, isRef, onScopeDispose, ref, shallowRef, watch } from \"vue\";\nimport type { NonGetHTTPMethod } from \"../api/api\";\nimport {\n isGetHook,\n isMutatorHook,\n type FragnoClientMutatorData,\n type FragnoClientHookData,\n} from \"./client\";\nimport type { FragnoClientError } from \"./client-error\";\nimport type { MaybeExtractPathParamsOrWiden, QueryParamsHint } from \"../api/internal/path\";\nimport type { InferOr } from \"../util/types-util\";\n\nexport type FragnoVueHook<\n _TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = (args?: {\n path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;\n query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;\n}) => {\n data: Ref<InferOr<TOutputSchema, undefined>>;\n loading: Ref<boolean>;\n error: Ref<FragnoClientError<TErrorCode[number]> | undefined>;\n};\n\nexport type FragnoVueMutator<\n _TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = () => {\n mutate: (args: {\n body?: InferOr<TInputSchema, undefined>;\n path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;\n query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;\n }) => Promise<InferOr<TOutputSchema, undefined>>;\n loading: Ref<boolean | undefined>;\n error: Ref<FragnoClientError<TErrorCode[number]> | undefined>;\n data: Ref<InferOr<TOutputSchema, undefined>>;\n};\n\n/**\n * Converts a Vue Ref to a NanoStore Atom.\n *\n * This is used to convert Vue refs to atoms, so that we can use them in the store.\n *\n * @private\n */\nexport function refToAtom<T>(ref: Ref<T>): ReadableAtom<T> {\n const a = atom(ref.value);\n\n watch(ref, (newVal) => {\n a.set(newVal);\n });\n\n // TODO: Do we need to unsubscribe, or is this handled by `onScopeDispose` below?\n\n return a;\n}\n\n// Helper function to create a Vue composable from a GET hook\n// We want 1 store per hook, so on updates to params, we need to update the store instead of creating a new one.\n// Nanostores only works with atoms (or strings), so we need to convert vue refs to atoms.\nfunction createVueHook<\n TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientHookData<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters>,\n): FragnoVueHook<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters> {\n return ({ path, query } = {}) => {\n const pathParams: Record<string, string | ReadableAtom<string>> = {};\n const queryParams: Record<string, string | ReadableAtom<string>> = {};\n\n for (const [key, value] of Object.entries(path ?? {})) {\n const v = value as string | Ref<string> | ReadableAtom<string>;\n pathParams[key] = isRef(v) ? refToAtom(v) : v;\n }\n\n for (const [key, value] of Object.entries(query ?? {})) {\n // Dunno why the cast is necessary\n const v = value as string | Ref<string> | ReadableAtom<string>;\n queryParams[key] = isRef(v) ? (refToAtom(v) as ReadableAtom<string>) : v;\n }\n\n const store = hook.store({\n path: pathParams as MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>,\n query: queryParams,\n });\n\n const data = ref();\n const loading = ref();\n const error = ref();\n\n const unsubscribe = store.subscribe((updatedStoreValue) => {\n data.value = updatedStoreValue.data;\n loading.value = updatedStoreValue.loading;\n error.value = updatedStoreValue.error;\n });\n\n if (getCurrentScope()) {\n onScopeDispose(() => {\n unsubscribe();\n });\n }\n\n return {\n data,\n loading,\n error,\n };\n };\n}\n\n// Helper function to create a Vue mutator from a mutator hook\nfunction createVueMutator<\n TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientMutatorData<\n TMethod,\n TPath,\n TInputSchema,\n TOutputSchema,\n TErrorCode,\n TQueryParameters\n >,\n): FragnoVueMutator<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters> {\n return () => {\n const store = useStore(hook.mutatorStore);\n\n // Create a wrapped mutate function that handles Vue refs\n const mutate = async (args: {\n body?: InferOr<TInputSchema, undefined>;\n path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;\n query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;\n }) => {\n const { body, path, query } = args;\n\n const pathParams: Record<string, string | ReadableAtom<string>> = {};\n const queryParams: Record<string, string | ReadableAtom<string>> = {};\n\n for (const [key, value] of Object.entries(path ?? {})) {\n const v = value as string | Ref<string> | ReadableAtom<string>;\n pathParams[key] = isRef(v) ? v.value : v;\n }\n\n for (const [key, value] of Object.entries(query ?? {})) {\n const v = value as string | Ref<string> | ReadableAtom<string>;\n queryParams[key] = isRef(v) ? v.value : v;\n }\n\n // Call the store's mutate function with normalized params\n return store.value.mutate({\n body,\n path: pathParams as MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>,\n query: queryParams,\n });\n };\n\n // Return the store-like object with Vue reactive refs\n return {\n mutate,\n loading: computed(() => store.value.loading),\n error: computed(() => store.value.error),\n data: computed(() => store.value.data) as Ref<InferOr<TOutputSchema, undefined>>,\n };\n };\n}\n\nexport function useFragno<T extends Record<string, unknown>>(\n clientObj: T,\n): {\n [K in keyof T]: T[K] extends FragnoClientHookData<\n \"GET\",\n infer TPath,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoVueHook<\"GET\", TPath, TOutputSchema, TErrorCode, TQueryParameters>\n : T[K] extends FragnoClientMutatorData<\n infer M,\n infer TPath,\n infer TInputSchema,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoVueMutator<M, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters>\n : T[K];\n} {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = {} as any;\n\n for (const key in clientObj) {\n if (!Object.prototype.hasOwnProperty.call(clientObj, key)) {\n continue;\n }\n\n const hook = clientObj[key];\n if (isGetHook(hook)) {\n result[key] = createVueHook(hook);\n } else if (isMutatorHook(hook)) {\n result[key] = createVueMutator(hook);\n } else {\n // Pass through non-hook values unchanged\n result[key] = hook;\n }\n }\n\n return result;\n}\n\nexport function useStore<SomeStore extends Store, Value extends StoreValue<SomeStore>>(\n store: SomeStore,\n): DeepReadonly<UnwrapNestedRefs<ShallowRef<Value>>> {\n const state = shallowRef();\n\n const unsubscribe = store.subscribe((value) => {\n state.value = value;\n });\n\n if (getCurrentScope()) {\n onScopeDispose(unsubscribe);\n }\n\n return state;\n}\n"],"mappings":";;;;;;;;;;;;AAuDA,SAAgB,UAAa,OAA8B;CACzD,MAAM,IAAI,KAAKA,MAAI,MAAM;AAEzB,OAAMA,QAAM,WAAW;AACrB,IAAE,IAAI,OAAO;GACb;AAIF,QAAO;;AAMT,SAAS,cAOP,MAC4E;AAC5E,SAAQ,EAAE,MAAM,UAAU,EAAE,KAAK;EAC/B,MAAMC,aAA4D,EAAE;EACpE,MAAMC,cAA6D,EAAE;AAErE,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE,CAAC,EAAE;GACrD,MAAM,IAAI;AACV,cAAW,OAAO,MAAM,EAAE,GAAG,UAAU,EAAE,GAAG;;AAG9C,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,EAAE,CAAC,EAAE;GAEtD,MAAM,IAAI;AACV,eAAY,OAAO,MAAM,EAAE,GAAI,UAAU,EAAE,GAA4B;;EAGzE,MAAM,QAAQ,KAAK,MAAM;GACvB,MAAM;GACN,OAAO;GACR,CAAC;EAEF,MAAM,OAAO,KAAK;EAClB,MAAM,UAAU,KAAK;EACrB,MAAM,QAAQ,KAAK;EAEnB,MAAM,cAAc,MAAM,WAAW,sBAAsB;AACzD,QAAK,QAAQ,kBAAkB;AAC/B,WAAQ,QAAQ,kBAAkB;AAClC,SAAM,QAAQ,kBAAkB;IAChC;AAEF,MAAI,iBAAiB,CACnB,sBAAqB;AACnB,gBAAa;IACb;AAGJ,SAAO;GACL;GACA;GACA;GACD;;;AAKL,SAAS,iBAQP,MAQ6F;AAC7F,cAAa;EACX,MAAM,QAAQ,SAAS,KAAK,aAAa;EAGzC,MAAM,SAAS,OAAO,SAIhB;GACJ,MAAM,EAAE,MAAM,MAAM,UAAU;GAE9B,MAAMD,aAA4D,EAAE;GACpE,MAAMC,cAA6D,EAAE;AAErE,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE,CAAC,EAAE;IACrD,MAAM,IAAI;AACV,eAAW,OAAO,MAAM,EAAE,GAAG,EAAE,QAAQ;;AAGzC,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,EAAE,CAAC,EAAE;IACtD,MAAM,IAAI;AACV,gBAAY,OAAO,MAAM,EAAE,GAAG,EAAE,QAAQ;;AAI1C,UAAO,MAAM,MAAM,OAAO;IACxB;IACA,MAAM;IACN,OAAO;IACR,CAAC;;AAIJ,SAAO;GACL;GACA,SAASC,iBAAe,MAAM,MAAM,QAAQ;GAC5C,OAAOA,iBAAe,MAAM,MAAM,MAAM;GACxC,MAAMA,iBAAe,MAAM,MAAM,KAAK;GACvC;;;AAIL,SAAgB,UACd,WAoBA;CAEA,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,WAAW;AAC3B,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,WAAW,IAAI,CACvD;EAGF,MAAM,OAAO,UAAU;AACvB,MAAI,UAAU,KAAK,CACjB,QAAO,OAAO,cAAc,KAAK;WACxB,cAAc,KAAK,CAC5B,QAAO,OAAO,iBAAiB,KAAK;MAGpC,QAAO,OAAO;;AAIlB,QAAO;;AAGT,SAAgB,SACd,OACmD;CACnD,MAAM,QAAQ,YAAY;CAE1B,MAAM,cAAc,MAAM,WAAW,UAAU;AAC7C,QAAM,QAAQ;GACd;AAEF,KAAI,iBAAiB,CACnB,gBAAe,YAAY;AAG7B,QAAO"}
|
|
1
|
+
{"version":3,"file":"vue.js","names":["ref","pathParams: Record<string, string | ReadableAtom<string>>","queryParams: Record<string, string | ReadableAtom<string>>","computed","result: any"],"sources":["../../src/client/vue.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { atom, type ReadableAtom, type Store, type StoreValue } from \"nanostores\";\nimport type { DeepReadonly, Ref, ShallowRef, UnwrapNestedRefs } from \"vue\";\nimport { computed, getCurrentScope, isRef, onScopeDispose, ref, shallowRef, watch } from \"vue\";\nimport type { NonGetHTTPMethod } from \"../api/api\";\nimport {\n isGetHook,\n isMutatorHook,\n isStore,\n type FragnoClientMutatorData,\n type FragnoClientHookData,\n type FragnoStoreData,\n} from \"./client\";\nimport { isReadableAtom } from \"../util/nanostores\";\nimport type { FragnoClientError } from \"./client-error\";\nimport type { MaybeExtractPathParamsOrWiden, QueryParamsHint } from \"../api/internal/path\";\nimport type { InferOr } from \"../util/types-util\";\n\nexport type FragnoVueHook<\n _TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = (args?: {\n path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;\n query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;\n}) => {\n data: Ref<InferOr<TOutputSchema, undefined>>;\n loading: Ref<boolean>;\n error: Ref<FragnoClientError<TErrorCode[number]> | undefined>;\n};\n\nexport type FragnoVueMutator<\n _TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n> = () => {\n mutate: (args: {\n body?: InferOr<TInputSchema, undefined>;\n path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;\n query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;\n }) => Promise<InferOr<TOutputSchema, undefined>>;\n loading: Ref<boolean | undefined>;\n error: Ref<FragnoClientError<TErrorCode[number]> | undefined>;\n data: Ref<InferOr<TOutputSchema, undefined>>;\n};\n\n/**\n * Type helper that unwraps any Store fields of the object into StoreValues\n */\nexport type FragnoVueStore<T extends object> = () => T extends Store<infer TStore>\n ? StoreValue<TStore>\n : {\n [K in keyof T]: T[K] extends Store ? StoreValue<T[K]> : T[K];\n };\n\n/**\n * Converts a Vue Ref to a NanoStore Atom.\n *\n * This is used to convert Vue refs to atoms, so that we can use them in the store.\n *\n * @private\n */\nexport function refToAtom<T>(ref: Ref<T>): ReadableAtom<T> {\n const a = atom(ref.value);\n\n watch(ref, (newVal) => {\n a.set(newVal);\n });\n\n // TODO: Do we need to unsubscribe, or is this handled by `onScopeDispose` below?\n\n return a;\n}\n\n// Helper function to create a Vue composable from a GET hook\n// We want 1 store per hook, so on updates to params, we need to update the store instead of creating a new one.\n// Nanostores only works with atoms (or strings), so we need to convert vue refs to atoms.\nfunction createVueHook<\n TMethod extends \"GET\",\n TPath extends string,\n TOutputSchema extends StandardSchemaV1,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientHookData<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters>,\n): FragnoVueHook<TMethod, TPath, TOutputSchema, TErrorCode, TQueryParameters> {\n return ({ path, query } = {}) => {\n const pathParams: Record<string, string | ReadableAtom<string>> = {};\n const queryParams: Record<string, string | ReadableAtom<string>> = {};\n\n for (const [key, value] of Object.entries(path ?? {})) {\n const v = value as string | Ref<string> | ReadableAtom<string>;\n pathParams[key] = isRef(v) ? refToAtom(v) : v;\n }\n\n for (const [key, value] of Object.entries(query ?? {})) {\n // Dunno why the cast is necessary\n const v = value as string | Ref<string> | ReadableAtom<string>;\n queryParams[key] = isRef(v) ? (refToAtom(v) as ReadableAtom<string>) : v;\n }\n\n const store = hook.store({\n path: pathParams as MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>,\n query: queryParams,\n });\n\n const data = ref();\n const loading = ref();\n const error = ref();\n\n const unsubscribe = store.subscribe((updatedStoreValue) => {\n data.value = updatedStoreValue.data;\n loading.value = updatedStoreValue.loading;\n error.value = updatedStoreValue.error;\n });\n\n if (getCurrentScope()) {\n onScopeDispose(() => {\n unsubscribe();\n });\n }\n\n return {\n data,\n loading,\n error,\n };\n };\n}\n\n// Helper function to create a Vue mutator from a mutator hook\nfunction createVueMutator<\n TMethod extends NonGetHTTPMethod,\n TPath extends string,\n TInputSchema extends StandardSchemaV1 | undefined,\n TOutputSchema extends StandardSchemaV1 | undefined,\n TErrorCode extends string,\n TQueryParameters extends string,\n>(\n hook: FragnoClientMutatorData<\n TMethod,\n TPath,\n TInputSchema,\n TOutputSchema,\n TErrorCode,\n TQueryParameters\n >,\n): FragnoVueMutator<TMethod, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters> {\n return () => {\n const store = useStore(hook.mutatorStore);\n\n // Create a wrapped mutate function that handles Vue refs\n const mutate = async (args: {\n body?: InferOr<TInputSchema, undefined>;\n path?: MaybeExtractPathParamsOrWiden<TPath, string | Ref<string> | ReadableAtom<string>>;\n query?: QueryParamsHint<TQueryParameters, string | Ref<string> | ReadableAtom<string>>;\n }) => {\n const { body, path, query } = args;\n\n const pathParams: Record<string, string | ReadableAtom<string>> = {};\n const queryParams: Record<string, string | ReadableAtom<string>> = {};\n\n for (const [key, value] of Object.entries(path ?? {})) {\n const v = value as string | Ref<string> | ReadableAtom<string>;\n pathParams[key] = isRef(v) ? v.value : v;\n }\n\n for (const [key, value] of Object.entries(query ?? {})) {\n const v = value as string | Ref<string> | ReadableAtom<string>;\n queryParams[key] = isRef(v) ? v.value : v;\n }\n\n // Call the store's mutate function with normalized params\n return store.value.mutate({\n body,\n path: pathParams as MaybeExtractPathParamsOrWiden<TPath, string | ReadableAtom<string>>,\n query: queryParams,\n });\n };\n\n // Return the store-like object with Vue reactive refs\n return {\n mutate,\n loading: computed(() => store.value.loading),\n error: computed(() => store.value.error),\n data: computed(() => store.value.data) as Ref<InferOr<TOutputSchema, undefined>>,\n };\n };\n}\n\n// Helper function to create a Vue composable from a store\nfunction createVueStore<const T extends object>(hook: FragnoStoreData<T>): FragnoVueStore<T> {\n if (isReadableAtom(hook.obj)) {\n return (() => useStore(hook.obj as Store).value) as FragnoVueStore<T>;\n }\n\n return (() => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result: any = {};\n\n for (const key in hook.obj) {\n if (!Object.prototype.hasOwnProperty.call(hook.obj, key)) {\n continue;\n }\n\n const value = hook.obj[key];\n if (isReadableAtom(value)) {\n result[key] = useStore(value).value;\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }) as FragnoVueStore<T>;\n}\n\nexport function useFragno<T extends Record<string, unknown>>(\n clientObj: T,\n): {\n [K in keyof T]: T[K] extends FragnoClientHookData<\n \"GET\",\n infer TPath,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoVueHook<\"GET\", TPath, TOutputSchema, TErrorCode, TQueryParameters>\n : T[K] extends FragnoClientMutatorData<\n infer M,\n infer TPath,\n infer TInputSchema,\n infer TOutputSchema,\n infer TErrorCode,\n infer TQueryParameters\n >\n ? FragnoVueMutator<M, TPath, TInputSchema, TOutputSchema, TErrorCode, TQueryParameters>\n : T[K] extends FragnoStoreData<infer TStoreObj>\n ? FragnoVueStore<TStoreObj>\n : T[K];\n} {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = {} as any;\n\n for (const key in clientObj) {\n if (!Object.prototype.hasOwnProperty.call(clientObj, key)) {\n continue;\n }\n\n const hook = clientObj[key];\n if (isGetHook(hook)) {\n result[key] = createVueHook(hook);\n } else if (isMutatorHook(hook)) {\n result[key] = createVueMutator(hook);\n } else if (isStore(hook)) {\n result[key] = createVueStore(hook);\n } else {\n // Pass through non-hook values unchanged\n result[key] = hook;\n }\n }\n\n return result;\n}\n\nexport function useStore<SomeStore extends Store, Value extends StoreValue<SomeStore>>(\n store: SomeStore,\n): DeepReadonly<UnwrapNestedRefs<ShallowRef<Value>>> {\n const state = shallowRef();\n\n const unsubscribe = store.subscribe((value) => {\n state.value = value;\n });\n\n if (getCurrentScope()) {\n onScopeDispose(unsubscribe);\n }\n\n return state;\n}\n"],"mappings":";;;;;;;;;;;;;AAmEA,SAAgB,UAAa,OAA8B;CACzD,MAAM,IAAI,KAAKA,MAAI,MAAM;AAEzB,OAAMA,QAAM,WAAW;AACrB,IAAE,IAAI,OAAO;GACb;AAIF,QAAO;;AAMT,SAAS,cAOP,MAC4E;AAC5E,SAAQ,EAAE,MAAM,UAAU,EAAE,KAAK;EAC/B,MAAMC,aAA4D,EAAE;EACpE,MAAMC,cAA6D,EAAE;AAErE,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE,CAAC,EAAE;GACrD,MAAM,IAAI;AACV,cAAW,OAAO,MAAM,EAAE,GAAG,UAAU,EAAE,GAAG;;AAG9C,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,EAAE,CAAC,EAAE;GAEtD,MAAM,IAAI;AACV,eAAY,OAAO,MAAM,EAAE,GAAI,UAAU,EAAE,GAA4B;;EAGzE,MAAM,QAAQ,KAAK,MAAM;GACvB,MAAM;GACN,OAAO;GACR,CAAC;EAEF,MAAM,OAAO,KAAK;EAClB,MAAM,UAAU,KAAK;EACrB,MAAM,QAAQ,KAAK;EAEnB,MAAM,cAAc,MAAM,WAAW,sBAAsB;AACzD,QAAK,QAAQ,kBAAkB;AAC/B,WAAQ,QAAQ,kBAAkB;AAClC,SAAM,QAAQ,kBAAkB;IAChC;AAEF,MAAI,iBAAiB,CACnB,sBAAqB;AACnB,gBAAa;IACb;AAGJ,SAAO;GACL;GACA;GACA;GACD;;;AAKL,SAAS,iBAQP,MAQ6F;AAC7F,cAAa;EACX,MAAM,QAAQ,SAAS,KAAK,aAAa;EAGzC,MAAM,SAAS,OAAO,SAIhB;GACJ,MAAM,EAAE,MAAM,MAAM,UAAU;GAE9B,MAAMD,aAA4D,EAAE;GACpE,MAAMC,cAA6D,EAAE;AAErE,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE,CAAC,EAAE;IACrD,MAAM,IAAI;AACV,eAAW,OAAO,MAAM,EAAE,GAAG,EAAE,QAAQ;;AAGzC,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,EAAE,CAAC,EAAE;IACtD,MAAM,IAAI;AACV,gBAAY,OAAO,MAAM,EAAE,GAAG,EAAE,QAAQ;;AAI1C,UAAO,MAAM,MAAM,OAAO;IACxB;IACA,MAAM;IACN,OAAO;IACR,CAAC;;AAIJ,SAAO;GACL;GACA,SAASC,iBAAe,MAAM,MAAM,QAAQ;GAC5C,OAAOA,iBAAe,MAAM,MAAM,MAAM;GACxC,MAAMA,iBAAe,MAAM,MAAM,KAAK;GACvC;;;AAKL,SAAS,eAAuC,MAA6C;AAC3F,KAAI,eAAe,KAAK,IAAI,CAC1B,eAAc,SAAS,KAAK,IAAa,CAAC;AAG5C,eAAc;EAEZ,MAAMC,SAAc,EAAE;AAEtB,OAAK,MAAM,OAAO,KAAK,KAAK;AAC1B,OAAI,CAAC,OAAO,UAAU,eAAe,KAAK,KAAK,KAAK,IAAI,CACtD;GAGF,MAAM,QAAQ,KAAK,IAAI;AACvB,OAAI,eAAe,MAAM,CACvB,QAAO,OAAO,SAAS,MAAM,CAAC;OAE9B,QAAO,OAAO;;AAIlB,SAAO;;;AAIX,SAAgB,UACd,WAsBA;CAEA,MAAM,SAAS,EAAE;AAEjB,MAAK,MAAM,OAAO,WAAW;AAC3B,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,WAAW,IAAI,CACvD;EAGF,MAAM,OAAO,UAAU;AACvB,MAAI,UAAU,KAAK,CACjB,QAAO,OAAO,cAAc,KAAK;WACxB,cAAc,KAAK,CAC5B,QAAO,OAAO,iBAAiB,KAAK;WAC3B,QAAQ,KAAK,CACtB,QAAO,OAAO,eAAe,KAAK;MAGlC,QAAO,OAAO;;AAIlB,QAAO;;AAGT,SAAgB,SACd,OACmD;CACnD,MAAM,QAAQ,YAAY;CAE1B,MAAM,cAAc,MAAM,WAAW,UAAU;AAC7C,QAAM,QAAQ;GACd;AAEF,KAAI,iBAAiB,CACnB,gBAAe,YAAY;AAG7B,QAAO"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/internal/trace-context.d.ts
|
|
2
|
+
type FragnoCoreTraceEvent = {
|
|
3
|
+
type: "route-input";
|
|
4
|
+
method: string;
|
|
5
|
+
path: string;
|
|
6
|
+
pathParams: Record<string, string>;
|
|
7
|
+
queryParams: [string, string][];
|
|
8
|
+
headers: [string, string][];
|
|
9
|
+
body: unknown;
|
|
10
|
+
} | {
|
|
11
|
+
type: "middleware-decision";
|
|
12
|
+
method: string;
|
|
13
|
+
path: string;
|
|
14
|
+
outcome: "allow" | "deny";
|
|
15
|
+
status?: number;
|
|
16
|
+
};
|
|
17
|
+
type FragnoTraceRecorder = (event: FragnoCoreTraceEvent) => void;
|
|
18
|
+
declare const runWithTraceRecorder: <T>(recorder: FragnoTraceRecorder, callback: () => T) => T;
|
|
19
|
+
declare const getTraceRecorder: () => FragnoTraceRecorder | undefined;
|
|
20
|
+
declare const recordTraceEvent: (event: FragnoCoreTraceEvent) => void;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { FragnoCoreTraceEvent, FragnoTraceRecorder, getTraceRecorder, recordTraceEvent, runWithTraceRecorder };
|
|
23
|
+
//# sourceMappingURL=trace-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-context.d.ts","names":[],"sources":["../../src/internal/trace-context.ts"],"sourcesContent":[],"mappings":";KAEY,oBAAA;EAAA,IAAA,EAAA,aAAA;EAkBA,MAAA,EAAA,MAAA;EAIC,IAAA,EAAA,MAAA;EAAqC,UAAA,EAjBhC,MAiBgC,CAAA,MAAA,EAAA,MAAA,CAAA;EAAqC,WAAA,EAAA,CAAA,MAAA,EAAA,MAAA,CAAA,EAAA;EAAI,OAAA,EAAA,CAAA,MAAA,EAAA,MAAA,CAAA,EAAA;EACrD,IAAA,EAAA,OAAA;AAEtC,CAAA,GAAa;EAEA,IAAA,EAAA,qBAKZ;;;;;;KAdW,mBAAA,WAA8B;cAI7B,oCAAqC,qCAAqC,MAAI;cAG9E,wBAAuB;cAEvB,0BAA2B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
3
|
+
//#region src/internal/trace-context.ts
|
|
4
|
+
const traceStorage = new AsyncLocalStorage();
|
|
5
|
+
const runWithTraceRecorder = (recorder, callback) => traceStorage.run(recorder, callback);
|
|
6
|
+
const getTraceRecorder = () => traceStorage.getStore();
|
|
7
|
+
const recordTraceEvent = (event) => {
|
|
8
|
+
const recorder = traceStorage.getStore();
|
|
9
|
+
if (recorder) recorder(event);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { getTraceRecorder, recordTraceEvent, runWithTraceRecorder };
|
|
14
|
+
//# sourceMappingURL=trace-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-context.js","names":[],"sources":["../../src/internal/trace-context.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\nexport type FragnoCoreTraceEvent =\n | {\n type: \"route-input\";\n method: string;\n path: string;\n pathParams: Record<string, string>;\n queryParams: [string, string][];\n headers: [string, string][];\n body: unknown;\n }\n | {\n type: \"middleware-decision\";\n method: string;\n path: string;\n outcome: \"allow\" | \"deny\";\n status?: number;\n };\n\nexport type FragnoTraceRecorder = (event: FragnoCoreTraceEvent) => void;\n\nconst traceStorage = new AsyncLocalStorage<FragnoTraceRecorder>();\n\nexport const runWithTraceRecorder = <T>(recorder: FragnoTraceRecorder, callback: () => T): T =>\n traceStorage.run(recorder, callback);\n\nexport const getTraceRecorder = (): FragnoTraceRecorder | undefined => traceStorage.getStore();\n\nexport const recordTraceEvent = (event: FragnoCoreTraceEvent): void => {\n const recorder = traceStorage.getStore();\n if (recorder) {\n recorder(event);\n }\n};\n"],"mappings":";;;AAsBA,MAAM,eAAe,IAAI,mBAAwC;AAEjE,MAAa,wBAA2B,UAA+B,aACrE,aAAa,IAAI,UAAU,SAAS;AAEtC,MAAa,yBAA0D,aAAa,UAAU;AAE9F,MAAa,oBAAoB,UAAsC;CACrE,MAAM,WAAW,aAAa,UAAU;AACxC,KAAI,SACF,UAAS,MAAM"}
|
package/dist/mod-client.d.ts
CHANGED
|
@@ -3,35 +3,13 @@ import { FragnoRouteConfig, RequestThisContext } from "./api/api.js";
|
|
|
3
3
|
import { BoundServices } from "./api/bind-services.js";
|
|
4
4
|
import { RouteFactory, RouteFactoryContext, defineRoute, defineRoutes } from "./api/route.js";
|
|
5
5
|
import { instantiatedFragmentFakeSymbol } from "./internal/symbols.js";
|
|
6
|
-
import { FragmentInstantiationBuilder, FragnoInstantiatedFragment } from "./api/fragment-instantiator.js";
|
|
6
|
+
import { FragmentInstantiationBuilder, FragnoInstantiatedFragment, IFragmentInstantiationBuilder, InstantiatedFragmentFromDefinition } from "./api/fragment-instantiator.js";
|
|
7
7
|
import { FragmentDefinition, FragmentDefinitionBuilder, ServiceConstructorFn, ServiceContext } from "./api/fragment-definition-builder.js";
|
|
8
|
+
import { FragnoRuntime, defaultFragnoRuntime } from "./runtime.js";
|
|
8
9
|
|
|
9
10
|
//#region src/mod-client.d.ts
|
|
10
|
-
declare function defineFragment(_name: string):
|
|
11
|
-
|
|
12
|
-
providesBaseService: () => /*elided*/any;
|
|
13
|
-
providesService: () => /*elided*/any;
|
|
14
|
-
providesPrivateService: () => /*elided*/any;
|
|
15
|
-
usesService: () => /*elided*/any;
|
|
16
|
-
usesOptionalService: () => /*elided*/any;
|
|
17
|
-
withRequestStorage: () => /*elided*/any;
|
|
18
|
-
withExternalRequestStorage: () => /*elided*/any;
|
|
19
|
-
withThisContext: () => /*elided*/any;
|
|
20
|
-
withLinkedFragment: () => /*elided*/any;
|
|
21
|
-
extend: () => /*elided*/any;
|
|
22
|
-
build: () => {};
|
|
23
|
-
};
|
|
24
|
-
declare function instantiate(_definition: unknown): {
|
|
25
|
-
withConfig: () => /*elided*/any;
|
|
26
|
-
withRoutes: () => /*elided*/any;
|
|
27
|
-
withOptions: () => /*elided*/any;
|
|
28
|
-
withServices: () => /*elided*/any;
|
|
29
|
-
build: () => {};
|
|
30
|
-
definition: {};
|
|
31
|
-
routes: never[];
|
|
32
|
-
config: undefined;
|
|
33
|
-
options: undefined;
|
|
34
|
-
};
|
|
11
|
+
declare function defineFragment(_name: string): object;
|
|
12
|
+
declare function instantiate(_definition: unknown): IFragmentInstantiationBuilder;
|
|
35
13
|
//#endregion
|
|
36
|
-
export { type BoundServices, type FragmentDefinition, FragmentDefinitionBuilder, type FragmentInstantiationBuilder, type FragnoInstantiatedFragment, type FragnoPublicConfig, type FragnoRouteConfig, type RequestThisContext, type RouteFactory, type RouteFactoryContext, type ServiceConstructorFn, type ServiceContext, defineFragment, defineRoute, defineRoutes, instantiate, instantiatedFragmentFakeSymbol };
|
|
14
|
+
export { type BoundServices, type FragmentDefinition, FragmentDefinitionBuilder, type FragmentInstantiationBuilder, type FragnoInstantiatedFragment, type FragnoPublicConfig, type FragnoRouteConfig, type FragnoRuntime, type InstantiatedFragmentFromDefinition, type RequestThisContext, type RouteFactory, type RouteFactoryContext, type ServiceConstructorFn, type ServiceContext, defaultFragnoRuntime, defineFragment, defineRoute, defineRoutes, instantiate, instantiatedFragmentFakeSymbol };
|
|
37
15
|
//# sourceMappingURL=mod-client.d.ts.map
|
package/dist/mod-client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod-client.d.ts","names":[],"sources":["../src/mod-client.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mod-client.d.ts","names":[],"sources":["../src/mod-client.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;iBAgCgB,cAAA;iBAyCA,WAAA,wBAAgC"}
|
package/dist/mod-client.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { instantiatedFragmentFakeSymbol } from "./internal/symbols.js";
|
|
1
2
|
import { FragmentDefinitionBuilder } from "./api/fragment-definition-builder.js";
|
|
3
|
+
import { defaultFragnoRuntime } from "./runtime.js";
|
|
2
4
|
import { defineRoute, defineRoutes } from "./api/route.js";
|
|
3
|
-
import { instantiatedFragmentFakeSymbol } from "./internal/symbols.js";
|
|
4
5
|
|
|
5
6
|
//#region src/mod-client.ts
|
|
6
7
|
function defineFragment(_name) {
|
|
7
|
-
const
|
|
8
|
+
const definitionStub = { name: _name };
|
|
9
|
+
const stub = new Proxy({
|
|
8
10
|
withDependencies: () => stub,
|
|
9
11
|
providesBaseService: () => stub,
|
|
10
12
|
providesService: () => stub,
|
|
@@ -16,25 +18,60 @@ function defineFragment(_name) {
|
|
|
16
18
|
withThisContext: () => stub,
|
|
17
19
|
withLinkedFragment: () => stub,
|
|
18
20
|
extend: () => stub,
|
|
19
|
-
build: () =>
|
|
20
|
-
|
|
21
|
+
build: () => definitionStub,
|
|
22
|
+
provideHooks: () => stub
|
|
23
|
+
}, { get(target, prop) {
|
|
24
|
+
if (prop in target) return target[prop];
|
|
25
|
+
return () => stub;
|
|
26
|
+
} });
|
|
21
27
|
return stub;
|
|
22
28
|
}
|
|
23
29
|
function instantiate(_definition) {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
const fragmentStubMethods = {
|
|
31
|
+
[instantiatedFragmentFakeSymbol]: instantiatedFragmentFakeSymbol,
|
|
32
|
+
name: "",
|
|
33
|
+
routes: [],
|
|
34
|
+
services: {},
|
|
35
|
+
mountRoute: "",
|
|
36
|
+
get $internal() {
|
|
37
|
+
return {
|
|
38
|
+
deps: {},
|
|
39
|
+
options: {},
|
|
40
|
+
linkedFragments: {}
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
withMiddleware: () => fragmentStub,
|
|
44
|
+
inContext: (callback) => callback(),
|
|
45
|
+
handlersFor: () => ({}),
|
|
46
|
+
handler: async () => new Response(),
|
|
47
|
+
callRoute: async () => ({
|
|
48
|
+
ok: true,
|
|
49
|
+
data: void 0,
|
|
50
|
+
error: void 0
|
|
51
|
+
}),
|
|
52
|
+
callRouteRaw: async () => new Response()
|
|
53
|
+
};
|
|
54
|
+
const fragmentStub = new Proxy(fragmentStubMethods, { get(target, prop) {
|
|
55
|
+
if (prop in target) return target[prop];
|
|
56
|
+
return () => fragmentStub;
|
|
57
|
+
} });
|
|
58
|
+
const builderStub = new Proxy({
|
|
59
|
+
withConfig: () => builderStub,
|
|
60
|
+
withRoutes: () => builderStub,
|
|
61
|
+
withOptions: () => builderStub,
|
|
62
|
+
withServices: () => builderStub,
|
|
63
|
+
build: () => fragmentStub,
|
|
30
64
|
definition: {},
|
|
31
65
|
routes: [],
|
|
32
66
|
config: void 0,
|
|
33
67
|
options: void 0
|
|
34
|
-
}
|
|
35
|
-
|
|
68
|
+
}, { get(target, prop) {
|
|
69
|
+
if (prop in target) return target[prop];
|
|
70
|
+
return () => builderStub;
|
|
71
|
+
} });
|
|
72
|
+
return builderStub;
|
|
36
73
|
}
|
|
37
74
|
|
|
38
75
|
//#endregion
|
|
39
|
-
export { FragmentDefinitionBuilder, defineFragment, defineRoute, defineRoutes, instantiate, instantiatedFragmentFakeSymbol };
|
|
76
|
+
export { FragmentDefinitionBuilder, defaultFragnoRuntime, defineFragment, defineRoute, defineRoutes, instantiate, instantiatedFragmentFakeSymbol };
|
|
40
77
|
//# sourceMappingURL=mod-client.js.map
|
package/dist/mod-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod-client.js","names":[],"sources":["../src/mod-client.ts"],"sourcesContent":["// ============================================================================\n// Client-side entry point for @fragno-dev/core\n// This file mirrors mod.ts but provides stub implementations for server-side\n// APIs that are stripped by unplugin-fragno during browser builds.\n// ============================================================================\n\n// ============================================================================\n// Fragment Definition and Instantiation\n// ============================================================================\n\n// Re-export types only\nexport type {\n FragmentDefinition,\n ServiceContext,\n ServiceConstructorFn,\n} from \"./api/fragment-definition-builder\";\n\nexport type {\n FragmentInstantiationBuilder,\n FragnoInstantiatedFragment,\n BoundServices,\n} from \"./api/fragment-instantiator\";\n\n// Stub implementation for defineFragment\n// This is stripped by unplugin-fragno in browser builds\nexport function defineFragment(_name: string) {\n const
|
|
1
|
+
{"version":3,"file":"mod-client.js","names":["stub: object","fragmentStub: IFragnoInstantiatedFragment","builderStub: IFragmentInstantiationBuilder"],"sources":["../src/mod-client.ts"],"sourcesContent":["// ============================================================================\n// Client-side entry point for @fragno-dev/core\n// This file mirrors mod.ts but provides stub implementations for server-side\n// APIs that are stripped by unplugin-fragno during browser builds.\n// ============================================================================\n\n// ============================================================================\n// Fragment Definition and Instantiation\n// ============================================================================\n\n// Re-export types only\nexport type {\n FragmentDefinition,\n ServiceContext,\n ServiceConstructorFn,\n} from \"./api/fragment-definition-builder\";\n\nexport type {\n FragmentInstantiationBuilder,\n FragnoInstantiatedFragment,\n BoundServices,\n InstantiatedFragmentFromDefinition,\n} from \"./api/fragment-instantiator\";\n\nimport type {\n IFragmentInstantiationBuilder,\n IFragnoInstantiatedFragment,\n} from \"./api/fragment-instantiator\";\nimport { instantiatedFragmentFakeSymbol } from \"./internal/symbols\";\n\n// Stub implementation for defineFragment\n// This is stripped by unplugin-fragno in browser builds\nexport function defineFragment(_name: string) {\n const definitionStub = {\n name: _name,\n };\n\n const stubMethods = {\n withDependencies: () => stub,\n providesBaseService: () => stub,\n providesService: () => stub,\n providesPrivateService: () => stub,\n usesService: () => stub,\n usesOptionalService: () => stub,\n withRequestStorage: () => stub,\n withExternalRequestStorage: () => stub,\n withThisContext: () => stub,\n withLinkedFragment: () => stub,\n extend: () => stub,\n build: () => definitionStub,\n // From fragno-db\n provideHooks: () => stub,\n };\n\n // Wrap with Proxy to handle any additional methods (e.g. from extend())\n const stub: object = new Proxy(stubMethods, {\n get(target, prop) {\n if (prop in target) {\n return target[prop as keyof typeof target];\n }\n // Return a function that returns the stub for method chaining\n return () => stub;\n },\n });\n\n return stub;\n}\n\n// Re-export the builder class (for type compatibility)\nexport { FragmentDefinitionBuilder } from \"./api/fragment-definition-builder\";\n\n// Stub implementation for instantiate\n// This is stripped by unplugin-fragno in browser builds\nexport function instantiate(_definition: unknown) {\n const fragmentStubMethods = {\n [instantiatedFragmentFakeSymbol]: instantiatedFragmentFakeSymbol,\n name: \"\",\n routes: [],\n services: {},\n mountRoute: \"\",\n get $internal() {\n return {\n deps: {},\n options: {},\n linkedFragments: {},\n };\n },\n withMiddleware: () => fragmentStub,\n inContext: <T>(callback: () => T) => callback(),\n handlersFor: () => ({}),\n handler: async () => new Response(),\n callRoute: async () => ({ ok: true, data: undefined, error: undefined }),\n callRouteRaw: async () => new Response(),\n };\n\n // Wrap with Proxy to handle any additional methods\n const fragmentStub: IFragnoInstantiatedFragment = new Proxy(\n fragmentStubMethods as IFragnoInstantiatedFragment,\n {\n get(target, prop) {\n if (prop in target) {\n return target[prop as keyof typeof target];\n }\n // Return a function that returns the stub for method chaining\n return () => fragmentStub;\n },\n },\n );\n\n const builderStubMethods = {\n withConfig: () => builderStub,\n withRoutes: () => builderStub,\n withOptions: () => builderStub,\n withServices: () => builderStub,\n build: () => fragmentStub,\n definition: {},\n routes: [],\n config: undefined,\n options: undefined,\n };\n\n // Wrap with Proxy to handle any additional methods\n const builderStub: IFragmentInstantiationBuilder = new Proxy(\n builderStubMethods as IFragmentInstantiationBuilder,\n {\n get(target, prop) {\n if (prop in target) {\n return target[prop as keyof typeof target];\n }\n // Return a function that returns the stub for method chaining\n return () => builderStub;\n },\n },\n );\n\n return builderStub;\n}\n\n// ============================================================================\n// Core Configuration\n// ============================================================================\nexport type { FragnoPublicConfig } from \"./api/shared-types\";\n\n// ============================================================================\n// Runtime\n// ============================================================================\nexport { defaultFragnoRuntime, type FragnoRuntime } from \"./runtime\";\n\n// ============================================================================\n// Route Definition\n// ============================================================================\nexport {\n defineRoute,\n defineRoutes,\n type RouteFactory,\n type RouteFactoryContext,\n} from \"./api/route\";\n\nexport type { FragnoRouteConfig, RequestThisContext } from \"./api/api\";\n\nexport { instantiatedFragmentFakeSymbol } from \"./internal/symbols\";\n"],"mappings":";;;;;;AAgCA,SAAgB,eAAe,OAAe;CAC5C,MAAM,iBAAiB,EACrB,MAAM,OACP;CAoBD,MAAMA,OAAe,IAAI,MAlBL;EAClB,wBAAwB;EACxB,2BAA2B;EAC3B,uBAAuB;EACvB,8BAA8B;EAC9B,mBAAmB;EACnB,2BAA2B;EAC3B,0BAA0B;EAC1B,kCAAkC;EAClC,uBAAuB;EACvB,0BAA0B;EAC1B,cAAc;EACd,aAAa;EAEb,oBAAoB;EACrB,EAG2C,EAC1C,IAAI,QAAQ,MAAM;AAChB,MAAI,QAAQ,OACV,QAAO,OAAO;AAGhB,eAAa;IAEhB,CAAC;AAEF,QAAO;;AAQT,SAAgB,YAAY,aAAsB;CAChD,MAAM,sBAAsB;GACzB,iCAAiC;EAClC,MAAM;EACN,QAAQ,EAAE;EACV,UAAU,EAAE;EACZ,YAAY;EACZ,IAAI,YAAY;AACd,UAAO;IACL,MAAM,EAAE;IACR,SAAS,EAAE;IACX,iBAAiB,EAAE;IACpB;;EAEH,sBAAsB;EACtB,YAAe,aAAsB,UAAU;EAC/C,oBAAoB,EAAE;EACtB,SAAS,YAAY,IAAI,UAAU;EACnC,WAAW,aAAa;GAAE,IAAI;GAAM,MAAM;GAAW,OAAO;GAAW;EACvE,cAAc,YAAY,IAAI,UAAU;EACzC;CAGD,MAAMC,eAA4C,IAAI,MACpD,qBACA,EACE,IAAI,QAAQ,MAAM;AAChB,MAAI,QAAQ,OACV,QAAO,OAAO;AAGhB,eAAa;IAEhB,CACF;CAeD,MAAMC,cAA6C,IAAI,MAb5B;EACzB,kBAAkB;EAClB,kBAAkB;EAClB,mBAAmB;EACnB,oBAAoB;EACpB,aAAa;EACb,YAAY,EAAE;EACd,QAAQ,EAAE;EACV,QAAQ;EACR,SAAS;EACV,EAKC,EACE,IAAI,QAAQ,MAAM;AAChB,MAAI,QAAQ,OACV,QAAO,OAAO;AAGhB,eAAa;IAEhB,CACF;AAED,QAAO"}
|
package/dist/mod.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { FragnoPublicConfig } from "./api/shared-types.js";
|
|
2
|
-
import { FragnoRouteConfig, RequestThisContext } from "./api/api.js";
|
|
2
|
+
import { FragnoRouteConfig, RequestThisContext, RouteContentType } from "./api/api.js";
|
|
3
3
|
import { BoundServices } from "./api/bind-services.js";
|
|
4
4
|
import { RouteFactory, RouteFactoryContext, defineRoute, defineRoutes } from "./api/route.js";
|
|
5
|
-
import { AnyFragnoInstantiatedFragment, FragmentInstantiationBuilder, FragnoInstantiatedFragment, instantiate } from "./api/fragment-instantiator.js";
|
|
5
|
+
import { AnyFragnoInstantiatedFragment, FragmentInstantiationBuilder, FragnoInstantiatedFragment, InstantiatedFragmentFromDefinition, instantiate } from "./api/fragment-instantiator.js";
|
|
6
6
|
import { ExtractLinkedServices, FragmentDefinition, FragmentDefinitionBuilder, LinkedFragmentCallback, ServiceConstructorFn, ServiceContext, defineFragment } from "./api/fragment-definition-builder.js";
|
|
7
|
-
|
|
7
|
+
import { FragnoRuntime, defaultFragnoRuntime } from "./runtime.js";
|
|
8
|
+
export { type AnyFragnoInstantiatedFragment, type BoundServices, type ExtractLinkedServices, type FragmentDefinition, FragmentDefinitionBuilder, type FragmentInstantiationBuilder, type FragnoInstantiatedFragment, type FragnoPublicConfig, type FragnoRouteConfig, type FragnoRuntime, type InstantiatedFragmentFromDefinition, type LinkedFragmentCallback, type RequestThisContext, type RouteContentType, type RouteFactory, type RouteFactoryContext, type ServiceConstructorFn, type ServiceContext, defaultFragnoRuntime, defineFragment, defineRoute, defineRoutes, instantiate };
|
package/dist/mod.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FragmentDefinitionBuilder, defineFragment } from "./api/fragment-definition-builder.js";
|
|
2
|
+
import { defaultFragnoRuntime } from "./runtime.js";
|
|
2
3
|
import { defineRoute, defineRoutes } from "./api/route.js";
|
|
3
4
|
import { instantiate } from "./api/fragment-instantiator.js";
|
|
4
5
|
|
|
5
|
-
export { FragmentDefinitionBuilder, defineFragment, defineRoute, defineRoutes, instantiate };
|
|
6
|
+
export { FragmentDefinitionBuilder, defaultFragnoRuntime, defineFragment, defineRoute, defineRoutes, instantiate };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/runtime.d.ts
|
|
2
|
+
type FragnoRuntime = {
|
|
3
|
+
time: {
|
|
4
|
+
now: () => Date;
|
|
5
|
+
};
|
|
6
|
+
random: {
|
|
7
|
+
float: () => number;
|
|
8
|
+
uuid: () => string;
|
|
9
|
+
cuid: () => string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
declare const defaultFragnoRuntime: FragnoRuntime;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { FragnoRuntime, defaultFragnoRuntime };
|
|
15
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","names":[],"sources":["../src/runtime.ts"],"sourcesContent":[],"mappings":";KAEY,aAAA;EAAA,IAAA,EAAA;IAoCC,GAAA,EAAA,GAAA,GAlCE,IAkCF;;;;;;;;cAAA,sBAAsB"}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createId } from "@paralleldrive/cuid2";
|
|
2
|
+
|
|
3
|
+
//#region src/runtime.ts
|
|
4
|
+
const fallbackUuid = () => {
|
|
5
|
+
const bytes = new Uint8Array(16);
|
|
6
|
+
for (let i = 0; i < bytes.length; i += 1) bytes[i] = Math.floor(Math.random() * 256);
|
|
7
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
8
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
9
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
|
|
10
|
+
return [
|
|
11
|
+
hex.slice(0, 4).join(""),
|
|
12
|
+
hex.slice(4, 6).join(""),
|
|
13
|
+
hex.slice(6, 8).join(""),
|
|
14
|
+
hex.slice(8, 10).join(""),
|
|
15
|
+
hex.slice(10, 16).join("")
|
|
16
|
+
].join("-");
|
|
17
|
+
};
|
|
18
|
+
const defaultUuid = () => {
|
|
19
|
+
const cryptoApi = globalThis.crypto;
|
|
20
|
+
return cryptoApi?.randomUUID ? cryptoApi.randomUUID() : fallbackUuid();
|
|
21
|
+
};
|
|
22
|
+
const defaultFragnoRuntime = {
|
|
23
|
+
time: { now: () => /* @__PURE__ */ new Date() },
|
|
24
|
+
random: {
|
|
25
|
+
float: () => Math.random(),
|
|
26
|
+
uuid: () => defaultUuid(),
|
|
27
|
+
cuid: () => createId()
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { defaultFragnoRuntime };
|
|
33
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","names":["defaultFragnoRuntime: FragnoRuntime"],"sources":["../src/runtime.ts"],"sourcesContent":["import { createId } from \"@paralleldrive/cuid2\";\n\nexport type FragnoRuntime = {\n time: {\n now: () => Date;\n };\n random: {\n float: () => number;\n uuid: () => string;\n cuid: () => string;\n };\n};\n\nconst fallbackUuid = () => {\n const bytes = new Uint8Array(16);\n for (let i = 0; i < bytes.length; i += 1) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n\n // RFC 4122 variant + version 4\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n\n const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\"));\n return [\n hex.slice(0, 4).join(\"\"),\n hex.slice(4, 6).join(\"\"),\n hex.slice(6, 8).join(\"\"),\n hex.slice(8, 10).join(\"\"),\n hex.slice(10, 16).join(\"\"),\n ].join(\"-\");\n};\n\nconst defaultUuid = () => {\n const cryptoApi = globalThis.crypto;\n return cryptoApi?.randomUUID ? cryptoApi.randomUUID() : fallbackUuid();\n};\n\nexport const defaultFragnoRuntime: FragnoRuntime = {\n time: {\n now: () => new Date(),\n },\n random: {\n float: () => Math.random(),\n uuid: () => defaultUuid(),\n cuid: () => createId(),\n },\n};\n"],"mappings":";;;AAaA,MAAM,qBAAqB;CACzB,MAAM,QAAQ,IAAI,WAAW,GAAG;AAChC,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,EACrC,OAAM,KAAK,KAAK,MAAM,KAAK,QAAQ,GAAG,IAAI;AAI5C,OAAM,KAAM,MAAM,KAAK,KAAQ;AAC/B,OAAM,KAAM,MAAM,KAAK,KAAQ;CAE/B,MAAM,MAAM,MAAM,KAAK,QAAQ,SAAS,KAAK,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC;AAC3E,QAAO;EACL,IAAI,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG;EACxB,IAAI,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG;EACxB,IAAI,MAAM,GAAG,EAAE,CAAC,KAAK,GAAG;EACxB,IAAI,MAAM,GAAG,GAAG,CAAC,KAAK,GAAG;EACzB,IAAI,MAAM,IAAI,GAAG,CAAC,KAAK,GAAG;EAC3B,CAAC,KAAK,IAAI;;AAGb,MAAM,oBAAoB;CACxB,MAAM,YAAY,WAAW;AAC7B,QAAO,WAAW,aAAa,UAAU,YAAY,GAAG,cAAc;;AAGxE,MAAaA,uBAAsC;CACjD,MAAM,EACJ,2BAAW,IAAI,MAAM,EACtB;CACD,QAAQ;EACN,aAAa,KAAK,QAAQ;EAC1B,YAAY,aAAa;EACzB,YAAY,UAAU;EACvB;CACF"}
|
package/dist/test/test.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { RequestThisContext } from "../api/api.js";
|
|
|
4
4
|
import { BoundServices } from "../api/bind-services.js";
|
|
5
5
|
import { AnyRouteOrFactory, FlattenRouteFactories } from "../api/route.js";
|
|
6
6
|
import { FragnoResponse } from "../api/fragno-response.js";
|
|
7
|
-
import { FragnoInstantiatedFragment } from "../api/fragment-instantiator.js";
|
|
7
|
+
import { AnyFragnoInstantiatedFragment, FragnoInstantiatedFragment, RoutesWithInternal } from "../api/fragment-instantiator.js";
|
|
8
8
|
import { FragmentDefinition, FragmentDefinitionBuilder } from "../api/fragment-definition-builder.js";
|
|
9
9
|
|
|
10
10
|
//#region src/test/test.d.ts
|
|
@@ -87,7 +87,7 @@ interface CreateFragmentForTestOptions<TConfig, TOptions extends FragnoPublicCon
|
|
|
87
87
|
* }
|
|
88
88
|
* ```
|
|
89
89
|
*/
|
|
90
|
-
declare function createFragmentForTest<TConfig, TOptions extends FragnoPublicConfig, TDeps, TBaseServices extends Record<string, unknown>, TServices extends Record<string, unknown>, TServiceDependencies, TPrivateServices extends Record<string, unknown>, TServiceThisContext extends RequestThisContext, THandlerThisContext extends RequestThisContext, TRequestStorage, const TRoutesOrFactories extends readonly AnyRouteOrFactory[]>(definition: FragmentDefinition<TConfig, TOptions, TDeps, TBaseServices, TServices, TServiceDependencies, TPrivateServices, TServiceThisContext, THandlerThisContext, TRequestStorage>, routesOrFactories: TRoutesOrFactories, options: CreateFragmentForTestOptions<TConfig, TOptions, TServiceDependencies>): FragnoInstantiatedFragment<FlattenRouteFactories<TRoutesOrFactories>, TDeps, BoundServices<TBaseServices & TServices>, TServiceThisContext, THandlerThisContext, TRequestStorage>;
|
|
90
|
+
declare function createFragmentForTest<TConfig, TOptions extends FragnoPublicConfig, TDeps, TBaseServices extends Record<string, unknown>, TServices extends Record<string, unknown>, TServiceDependencies, TPrivateServices extends Record<string, unknown>, TServiceThisContext extends RequestThisContext, THandlerThisContext extends RequestThisContext, TRequestStorage, const TRoutesOrFactories extends readonly AnyRouteOrFactory[], TLinkedFragments extends Record<string, AnyFragnoInstantiatedFragment> = {}>(definition: FragmentDefinition<TConfig, TOptions, TDeps, TBaseServices, TServices, TServiceDependencies, TPrivateServices, TServiceThisContext, THandlerThisContext, TRequestStorage, TLinkedFragments>, routesOrFactories: TRoutesOrFactories, options: CreateFragmentForTestOptions<TConfig, TOptions, TServiceDependencies>): FragnoInstantiatedFragment<RoutesWithInternal<FlattenRouteFactories<TRoutesOrFactories>, TLinkedFragments>, TDeps, BoundServices<TBaseServices & TServices>, TServiceThisContext, THandlerThisContext, TRequestStorage, TOptions, TLinkedFragments>;
|
|
91
91
|
//#endregion
|
|
92
92
|
export { CreateFragmentForTestOptions, type FragnoResponse, type RouteHandlerInputOptions, TestBaseServices, createFragmentForTest, withTestUtils };
|
|
93
93
|
//# sourceMappingURL=test.d.ts.map
|
package/dist/test/test.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.d.ts","names":[],"sources":["../../src/test/test.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"test.d.ts","names":[],"sources":["../../src/test/test.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;KAoBY;;AAAZ;AAsBA;EAGqB,IAAA,EArBb,KAqBa;CAMW;;;;;;;;;;;;;;;;AAoB5B,iBA7BY,aAAA,CAAA,CA6BZ,EAAA,CAAA,OAAA,EAAA,iBA1BiB,kBA0BjB,EAAA,KAAA,EAAA,aAAA,EAAA,SAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,4BApB4B,kBAoB5B,EAAA,4BAnB4B,kBAmB5B,EAAA,eAAA,CAAA,CAAA,OAAA,EAhBS,yBAgBT,CAfE,OAeF,EAdE,QAcF,EAbE,KAaF,EAZE,aAYF,EAXE,SAWF,EAVE,YAUF,EATE,gBASF,EARE,mBAQF,EAPE,mBAOF,EANE,eAMF,CAAA,EAAA,GAJC,yBAID,CAHA,OAGA,EAFA,QAEA,EADA,KACA,EAAA,aAAA,GAAgB,gBAAhB,CAAiC,KAAjC,CAAA,EACA,SADA,EAEA,YAFA,EAGA,gBAHA,EAIA,mBAJA,EAKA,mBALA,EAMA,eANA,CAAA;;;;AAEA,UA+Da,4BA/Db,CAAA,OAAA,EAAA,iBAiEe,kBAjEf,EAAA,oBAAA,CAAA,CAAA;EACA,MAAA,EAmEM,OAnEN;EACA,OAAA,CAAA,EAmEQ,OAnER,CAmEgB,QAnEhB,CAAA;EACA,sBAAA,CAAA,EAmEuB,oBAnEvB;;;;AA4DJ;;;;;;;AA2DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG,iBA7Ba,qBA6Bb,CAAA,OAAA,EAAA,iBA3BgB,kBA2BhB,EAAA,KAAA,EAAA,sBAzBqB,MAyBrB,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,kBAxBiB,MAwBjB,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,oBAAA,EAAA,yBAtBwB,MAsBxB,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,4BArB2B,kBAqB3B,EAAA,4BApB2B,kBAoB3B,EAAA,eAAA,EAAA,iCAAA,SAlByC,iBAkBzC,EAAA,EAAA,yBAjBwB,MAiBxB,CAAA,MAAA,EAjBuC,6BAiBvC,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,UAAA,EAfW,kBAeX,CAdC,OAcD,EAbC,QAaD,EAZC,KAYD,EAXC,aAWD,EAVC,SAUD,EATC,oBASD,EARC,gBAQD,EAPC,mBAOD,EANC,mBAMD,EALC,eAKD,EAJC,gBAID,CAAA,EAAA,iBAAA,EAFkB,kBAElB,EAAA,OAAA,EADQ,4BACR,CADqC,OACrC,EAD8C,QAC9C,EADwD,oBACxD,CAAA,CAAA,EAAA,0BAAA,CACD,kBADC,CACkB,qBADlB,CACwC,kBADxC,CAAA,EAC6D,gBAD7D,CAAA,EAED,KAFC,EAGD,aAHC,CAGa,aAHb,GAG6B,SAH7B,CAAA,EAID,mBAJC,EAKD,mBALC,EAMD,eANC,EAOD,QAPC,EAQD,gBARC,CAAA"}
|
package/dist/test/test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.js","names":["newBaseServices: ServiceConstructorFn<\n TConfig,\n TOptions,\n TDeps,\n TServiceDeps,\n TPrivateServices,\n TBaseServices & TestBaseServices<TDeps>,\n TServiceThisContext\n >","testUtils: TestBaseServices<TDeps>"],"sources":["../../src/test/test.ts"],"sourcesContent":["import type { RequestThisContext } from \"../api/api\";\nimport type { AnyRouteOrFactory, FlattenRouteFactories } from \"../api/route\";\nimport type { FragnoPublicConfig } from \"../api/shared-types\";\nimport {\n FragmentDefinitionBuilder,\n type FragmentDefinition,\n type ServiceConstructorFn,\n} from \"../api/fragment-definition-builder\";\nimport {
|
|
1
|
+
{"version":3,"file":"test.js","names":["newBaseServices: ServiceConstructorFn<\n TConfig,\n TOptions,\n TDeps,\n TServiceDeps,\n TPrivateServices,\n TBaseServices & TestBaseServices<TDeps>,\n TServiceThisContext\n >","testUtils: TestBaseServices<TDeps>"],"sources":["../../src/test/test.ts"],"sourcesContent":["import type { RequestThisContext } from \"../api/api\";\nimport type { AnyRouteOrFactory, FlattenRouteFactories } from \"../api/route\";\nimport type { FragnoPublicConfig } from \"../api/shared-types\";\nimport {\n FragmentDefinitionBuilder,\n type FragmentDefinition,\n type ServiceConstructorFn,\n} from \"../api/fragment-definition-builder\";\nimport {\n instantiateFragment,\n type AnyFragnoInstantiatedFragment,\n type FragnoInstantiatedFragment,\n type RoutesWithInternal,\n} from \"../api/fragment-instantiator\";\nimport type { BoundServices } from \"../api/bind-services\";\n\n// Re-export for convenience\nexport type { RouteHandlerInputOptions } from \"../api/route-handler-input-options\";\nexport type { FragnoResponse } from \"../api/fragno-response\";\n\nexport type TestBaseServices<TDeps> = {\n /**\n * Access to fragment dependencies for testing purposes.\n */\n deps: TDeps;\n};\n\n/**\n * Extension function that adds test utilities to a fragment definition.\n * This adds a `test` service to base services with access to deps.\n *\n * @example\n * ```typescript\n * const definition = defineFragment(\"my-fragment\")\n * .withDependencies(({ config }) => ({ client: createClient(config) }))\n * .extend(withTestUtils())\n * .build();\n *\n * const fragment = createFragmentForTest(definition, [], { config: {...} });\n * expect(fragment.services.test.deps.client).toBeDefined();\n * ```\n */\nexport function withTestUtils() {\n return <\n TConfig,\n TOptions extends FragnoPublicConfig,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDeps,\n TPrivateServices,\n TServiceThisContext extends RequestThisContext,\n THandlerThisContext extends RequestThisContext,\n TRequestStorage,\n >(\n builder: FragmentDefinitionBuilder<\n TConfig,\n TOptions,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDeps,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage\n >,\n ): FragmentDefinitionBuilder<\n TConfig,\n TOptions,\n TDeps,\n TBaseServices & TestBaseServices<TDeps>,\n TServices,\n TServiceDeps,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage\n > => {\n // Get the current base services factory\n const currentBaseDef = builder.build();\n const currentBaseServices = currentBaseDef.baseServices;\n\n // Create new base services factory that merges test utilities\n const newBaseServices: ServiceConstructorFn<\n TConfig,\n TOptions,\n TDeps,\n TServiceDeps,\n TPrivateServices,\n TBaseServices & TestBaseServices<TDeps>,\n TServiceThisContext\n > = (context) => {\n // Call existing base services if they exist\n const existingServices = currentBaseServices\n ? currentBaseServices(context)\n : ({} as TBaseServices);\n\n // Add test utilities\n const testUtils: TestBaseServices<TDeps> = {\n deps: context.deps,\n };\n\n return {\n ...existingServices,\n ...testUtils,\n } as TBaseServices & TestBaseServices<TDeps>;\n };\n\n // Create new builder with updated base services\n return new FragmentDefinitionBuilder<\n TConfig,\n TOptions,\n TDeps,\n TBaseServices & TestBaseServices<TDeps>,\n TServices,\n TServiceDeps,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage\n >(builder.name, {\n dependencies: currentBaseDef.dependencies,\n baseServices: newBaseServices,\n namedServices: currentBaseDef.namedServices,\n privateServices: currentBaseDef.privateServices,\n serviceDependencies: currentBaseDef.serviceDependencies,\n createRequestStorage: currentBaseDef.createRequestStorage,\n createThisContext: currentBaseDef.createThisContext,\n });\n };\n}\n\n/**\n * Options for creating a test fragment with the new architecture\n */\nexport interface CreateFragmentForTestOptions<\n TConfig,\n TOptions extends FragnoPublicConfig,\n TServiceDependencies,\n> {\n config: TConfig;\n options?: Partial<TOptions>;\n serviceImplementations?: TServiceDependencies;\n}\n\n/**\n * Create a fragment instance for testing with optional service dependency overrides.\n * This uses the new fragment definition and instantiation architecture.\n *\n * **Important:** Use `.extend(withTestUtils())` before `.build()` to expose deps via `services.test.deps`.\n *\n * Returns an instantiated fragment with:\n * - `services` - Services (base + named) from the fragment definition\n * - `services.test.deps` - Dependencies (only if you used .extend(withTestUtils()))\n * - `callRoute()` - Type-safe method to call routes directly\n * - `handler()` - Request handler for integration\n * - `inContext()` - Run code within request context\n *\n * @param definition - The fragment definition from builder.build()\n * @param routesOrFactories - Route configurations or route factories\n * @param options - Configuration and optional overrides\n * @returns An instantiated fragment ready for testing\n *\n * @example\n * ```typescript\n * const definition = defineFragment<{ apiKey: string }>(\"test\")\n * .withDependencies(({ config }) => ({ client: createClient(config.apiKey) }))\n * .providesService(\"api\", ({ deps }) => ({ call: () => deps.client.call() }))\n * .extend(withTestUtils()) // <- Add test utilities\n * .build();\n *\n * const fragment = createFragmentForTest(\n * definition,\n * [route1, route2],\n * {\n * config: { apiKey: \"test-key\" },\n * options: { mountRoute: \"/api/test\" }\n * }\n * );\n *\n * // Access deps via test utilities\n * expect(fragment.services.test.deps.client).toBeDefined();\n * expect(fragment.services.api.call()).toBeDefined();\n *\n * // Call routes directly by method and path\n * const response = await fragment.callRoute(\"POST\", \"/login\", {\n * body: { username: \"test\", password: \"test123\" }\n * });\n *\n * if (response.type === 'json') {\n * expect(response.data).toEqual({...});\n * }\n * ```\n */\nexport function createFragmentForTest<\n TConfig,\n TOptions extends FragnoPublicConfig,\n TDeps,\n TBaseServices extends Record<string, unknown>,\n TServices extends Record<string, unknown>,\n TServiceDependencies,\n TPrivateServices extends Record<string, unknown>,\n TServiceThisContext extends RequestThisContext,\n THandlerThisContext extends RequestThisContext,\n TRequestStorage,\n const TRoutesOrFactories extends readonly AnyRouteOrFactory[],\n TLinkedFragments extends Record<string, AnyFragnoInstantiatedFragment> = {},\n>(\n definition: FragmentDefinition<\n TConfig,\n TOptions,\n TDeps,\n TBaseServices,\n TServices,\n TServiceDependencies,\n TPrivateServices,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n TLinkedFragments\n >,\n routesOrFactories: TRoutesOrFactories,\n options: CreateFragmentForTestOptions<TConfig, TOptions, TServiceDependencies>,\n): FragnoInstantiatedFragment<\n RoutesWithInternal<FlattenRouteFactories<TRoutesOrFactories>, TLinkedFragments>,\n TDeps,\n BoundServices<TBaseServices & TServices>,\n TServiceThisContext,\n THandlerThisContext,\n TRequestStorage,\n TOptions,\n TLinkedFragments\n> {\n const { config, options: fragmentOptions = {} as TOptions, serviceImplementations } = options;\n\n // Use default mountRoute for testing if not provided\n const fullOptions = {\n mountRoute: \"/api/test\",\n ...fragmentOptions,\n } as TOptions;\n\n // Instantiate and return the fragment directly\n return instantiateFragment(\n definition,\n config,\n routesOrFactories,\n fullOptions,\n serviceImplementations,\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,gBAAgB;AAC9B,SAYE,YAuBG;EAEH,MAAM,iBAAiB,QAAQ,OAAO;EACtC,MAAM,sBAAsB,eAAe;EAG3C,MAAMA,mBAQD,YAAY;GAEf,MAAM,mBAAmB,sBACrB,oBAAoB,QAAQ,GAC3B,EAAE;GAGP,MAAMC,YAAqC,EACzC,MAAM,QAAQ,MACf;AAED,UAAO;IACL,GAAG;IACH,GAAG;IACJ;;AAIH,SAAO,IAAI,0BAWT,QAAQ,MAAM;GACd,cAAc,eAAe;GAC7B,cAAc;GACd,eAAe,eAAe;GAC9B,iBAAiB,eAAe;GAChC,qBAAqB,eAAe;GACpC,sBAAsB,eAAe;GACrC,mBAAmB,eAAe;GACnC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkEN,SAAgB,sBAcd,YAaA,mBACA,SAUA;CACA,MAAM,EAAE,QAAQ,SAAS,kBAAkB,EAAE,EAAc,2BAA2B;AAStF,QAAO,oBACL,YACA,QACA,mBATkB;EAClB,YAAY;EACZ,GAAG;EACJ,EAQC,uBACD"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fragno-dev/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"exports": {
|
|
5
5
|
".": {
|
|
6
|
-
"
|
|
6
|
+
"workerd": {
|
|
7
|
+
"development": "./src/mod.ts",
|
|
8
|
+
"default": "./dist/mod.js"
|
|
9
|
+
},
|
|
10
|
+
"development": {
|
|
11
|
+
"browser": "./src/mod-client.ts",
|
|
12
|
+
"default": "./src/mod.ts"
|
|
13
|
+
},
|
|
7
14
|
"browser": "./dist/mod-client.js",
|
|
8
15
|
"types": "./dist/mod.d.ts",
|
|
9
16
|
"default": "./dist/mod.js"
|
|
@@ -33,6 +40,11 @@
|
|
|
33
40
|
"types": "./dist/api/request-context-storage.d.ts",
|
|
34
41
|
"default": "./dist/api/request-context-storage.js"
|
|
35
42
|
},
|
|
43
|
+
"./internal/trace-context": {
|
|
44
|
+
"development": "./src/internal/trace-context.ts",
|
|
45
|
+
"types": "./dist/internal/trace-context.d.ts",
|
|
46
|
+
"default": "./dist/internal/trace-context.js"
|
|
47
|
+
},
|
|
36
48
|
"./internal/symbols": {
|
|
37
49
|
"development": "./src/internal/symbols.ts",
|
|
38
50
|
"types": "./dist/internal/symbols.d.ts",
|
|
@@ -81,29 +93,30 @@
|
|
|
81
93
|
"type": "module",
|
|
82
94
|
"sideEffects": false,
|
|
83
95
|
"dependencies": {
|
|
96
|
+
"@paralleldrive/cuid2": "^2.3.1",
|
|
84
97
|
"@nanostores/query": "^0.3.4",
|
|
85
98
|
"@nanostores/solid": "^1.1.1",
|
|
86
|
-
"@standard-schema/spec": "^1.
|
|
87
|
-
"nanostores": "^1.0
|
|
88
|
-
"rou3": "^0.7.
|
|
99
|
+
"@standard-schema/spec": "^1.1.0",
|
|
100
|
+
"nanostores": "^1.1.0",
|
|
101
|
+
"rou3": "^0.7.12"
|
|
89
102
|
},
|
|
90
103
|
"devDependencies": {
|
|
91
|
-
"@sveltejs/vite-plugin-svelte": "^6.2.
|
|
92
|
-
"@testing-library/react": "^16.3.
|
|
93
|
-
"@testing-library/svelte": "^5.
|
|
104
|
+
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
105
|
+
"@testing-library/react": "^16.3.2",
|
|
106
|
+
"@testing-library/svelte": "^5.3.1",
|
|
94
107
|
"@testing-library/vue": "^8.1.0",
|
|
95
|
-
"@types/node": "^22",
|
|
96
|
-
"@types/react": "^19.
|
|
97
|
-
"@types/react-dom": "^19.
|
|
108
|
+
"@types/node": "^22.19.7",
|
|
109
|
+
"@types/react": "^19.2.8",
|
|
110
|
+
"@types/react-dom": "^19.2.3",
|
|
98
111
|
"@vitest/coverage-istanbul": "^3.2.4",
|
|
99
|
-
"happy-dom": "^20.
|
|
100
|
-
"react": "^19.0.
|
|
101
|
-
"react-dom": "^19.0.
|
|
102
|
-
"
|
|
103
|
-
"
|
|
112
|
+
"happy-dom": "^20.3.3",
|
|
113
|
+
"react": "^19.0.3",
|
|
114
|
+
"react-dom": "^19.0.3",
|
|
115
|
+
"solid-js": "^1.9.10",
|
|
116
|
+
"svelte": "^5.47.0",
|
|
104
117
|
"vitest": "^3.2.4",
|
|
105
|
-
"vue": "^3",
|
|
106
|
-
"zod": "^4.
|
|
118
|
+
"vue": "^3.5.27",
|
|
119
|
+
"zod": "^4.3.5",
|
|
107
120
|
"@fragno-private/typescript-config": "0.0.1",
|
|
108
121
|
"@fragno-private/vitest-config": "0.0.0"
|
|
109
122
|
},
|
package/src/api/api.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
|
2
2
|
import type { RequestInputContext } from "./request-input-context";
|
|
3
3
|
import type { RequestOutputContext } from "./request-output-context";
|
|
4
4
|
|
|
5
|
+
export type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
6
|
+
|
|
5
7
|
export type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
|
6
8
|
export type NonGetHTTPMethod = Exclude<HTTPMethod, "GET">;
|
|
7
9
|
|
|
@@ -25,6 +27,17 @@ export type ValidPath<T extends string = string> = T extends `/${infer Rest}`
|
|
|
25
27
|
|
|
26
28
|
export interface RequestThisContext {}
|
|
27
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Content types that can be accepted by a route.
|
|
32
|
+
*
|
|
33
|
+
* - `"application/json"` (default): JSON request body, validated against inputSchema
|
|
34
|
+
* - `"multipart/form-data"`: FormData request body (file uploads), no schema validation
|
|
35
|
+
*/
|
|
36
|
+
export type RouteContentType =
|
|
37
|
+
| "application/json"
|
|
38
|
+
| "multipart/form-data"
|
|
39
|
+
| "application/octet-stream";
|
|
40
|
+
|
|
28
41
|
export interface FragnoRouteConfig<
|
|
29
42
|
TMethod extends HTTPMethod,
|
|
30
43
|
TPath extends string,
|
|
@@ -36,6 +49,17 @@ export interface FragnoRouteConfig<
|
|
|
36
49
|
> {
|
|
37
50
|
method: TMethod;
|
|
38
51
|
path: TPath;
|
|
52
|
+
/**
|
|
53
|
+
* The expected content type for this route's request body.
|
|
54
|
+
*
|
|
55
|
+
* - `"application/json"` (default): Expects JSON body, will be validated against inputSchema
|
|
56
|
+
* - `"multipart/form-data"`: Expects FormData body (for file uploads), use `ctx.formData()` in handler
|
|
57
|
+
*
|
|
58
|
+
* The server will reject requests with mismatched Content-Type headers.
|
|
59
|
+
*
|
|
60
|
+
* @default "application/json"
|
|
61
|
+
*/
|
|
62
|
+
contentType?: RouteContentType;
|
|
39
63
|
inputSchema?: TInputSchema;
|
|
40
64
|
outputSchema?: TOutputSchema;
|
|
41
65
|
errorCodes?: readonly TErrorCode[];
|