@analogjs/router 3.0.0-alpha.17 → 3.0.0-alpha.18
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/fesm2022/analogjs-router-server-actions.mjs.map +1 -1
- package/fesm2022/analogjs-router-server.mjs.map +1 -1
- package/fesm2022/analogjs-router-tanstack-query.mjs.map +1 -1
- package/fesm2022/analogjs-router-tokens.mjs.map +1 -1
- package/fesm2022/analogjs-router.mjs.map +1 -1
- package/fesm2022/debug.page.mjs.map +1 -1
- package/fesm2022/routes.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analogjs-router-server-actions.mjs","names":[],"sources":["../../../../packages/router/server/actions/src/actions.ts","../../../../packages/router/server/actions/src/parse-request-data.ts","../../../../packages/router/server/actions/src/validate.ts","../../../../packages/router/server/actions/src/define-action.ts","../../../../packages/router/server/actions/src/define-server-route.ts","../../../../packages/router/server/actions/src/define-page-load.ts"],"sourcesContent":["import type { H3Event, H3EventContext } from 'nitro/h3';\nimport type { $Fetch } from 'nitro/types';\nimport type { NodeContext } from '../../../src/lib/route-types.js';\n\nexport type PageServerAction = {\n params: H3EventContext['params'];\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n};\n\nexport function fail<T = object>(status: number, errors: T): Response {\n return new Response(JSON.stringify(errors), {\n status,\n headers: {\n 'X-Analog-Errors': 'true',\n },\n });\n}\n\nexport function json<T = object>(data: T, config?: ResponseInit): Response {\n return new Response(JSON.stringify(data), {\n headers: {\n 'Content-Type': 'application/json; charset=utf-8',\n },\n ...config,\n });\n}\n\nexport function redirect(\n url: string,\n config: number | ResponseInit = 302,\n): Response {\n if (typeof config === 'number') {\n return new Response(null, {\n status: config,\n headers: {\n Location: `${url}`,\n },\n });\n }\n\n return new Response(null, {\n headers: {\n Location: `${url}`,\n },\n ...config,\n });\n}\n","import { readBody, readFormData, toRequest as h3ToRequest } from 'nitro/h3';\n\ntype RequestEntryValue = string | File;\ntype ParsedRequestValue = RequestEntryValue | RequestEntryValue[];\n\nfunction appendEntry(\n target: Record<string, ParsedRequestValue>,\n key: string,\n value: RequestEntryValue,\n) {\n const existingValue = target[key];\n\n if (existingValue === undefined) {\n target[key] = value;\n return;\n }\n\n if (Array.isArray(existingValue)) {\n existingValue.push(value);\n return;\n }\n\n target[key] = [existingValue, value];\n}\n\nfunction getRequest(event: { method: string; headers: Headers }): Request {\n const maybeRequest = (event as unknown as { request?: Request }).request;\n if (maybeRequest) {\n return maybeRequest;\n }\n return h3ToRequest(event as Parameters<typeof h3ToRequest>[0]);\n}\n\nfunction getContentType(event: { method: string; headers: Headers }): string {\n const request = getRequest(event);\n\n return (\n request.headers.get('content-type') ??\n event.headers.get('content-type') ??\n event.headers.get('Content-Type') ??\n ''\n );\n}\n\nfunction isJsonContentType(contentType: string): boolean {\n const mimeType = contentType.split(';', 1)[0]?.trim().toLowerCase() ?? '';\n return mimeType === 'application/json' || mimeType.endsWith('+json');\n}\n\nfunction isFormContentType(contentType: string): boolean {\n return (\n contentType.includes('multipart/form-data') ||\n contentType.includes('application/x-www-form-urlencoded')\n );\n}\n\nexport function parseSearchParams(\n searchParams: URLSearchParams,\n): Record<string, ParsedRequestValue> {\n const result: Record<string, ParsedRequestValue> = {};\n searchParams.forEach((value, key) => {\n appendEntry(result, key, value);\n });\n return result;\n}\n\nexport function parseFormData(\n formData: FormData,\n): Record<string, ParsedRequestValue> {\n const result: Record<string, ParsedRequestValue> = {};\n formData.forEach((value, key) => {\n appendEntry(result, key, value as RequestEntryValue);\n });\n return result;\n}\n\nexport async function parseRequestData(event: {\n method: string;\n headers: Headers;\n}): Promise<unknown> {\n const request = getRequest(event);\n const httpEvent = event as unknown as Parameters<typeof readBody>[0];\n const h3Event = event as unknown as Parameters<typeof readFormData>[0];\n const method = event.method.toUpperCase();\n\n if (method === 'GET' || method === 'HEAD') {\n const url = new URL(request.url, 'http://localhost');\n return parseSearchParams(url.searchParams);\n }\n\n const contentType = getContentType(event);\n\n if (isJsonContentType(contentType)) {\n try {\n return (await readBody(httpEvent)) ?? {};\n } catch {\n try {\n return await request.json();\n } catch {\n return {};\n }\n }\n }\n\n if (isFormContentType(contentType)) {\n try {\n return parseFormData(await readFormData(h3Event));\n } catch {\n if (typeof request.formData === 'function') {\n return parseFormData(await request.formData());\n }\n\n return {};\n }\n }\n\n try {\n return (await readBody(httpEvent)) ?? {};\n } catch {\n try {\n return await request.json();\n } catch {\n return {};\n }\n }\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\n\n/**\n * Validates unknown input against a Standard Schema.\n *\n * Handles both sync and async `validate` implementations — the Standard\n * Schema spec allows either return shape.\n */\nexport async function validateWithSchema<T extends StandardSchemaV1>(\n schema: T,\n data: unknown,\n): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<T>>> {\n return schema['~standard'].validate(data);\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { H3Event, H3EventContext } from 'nitro/h3';\nimport type { $Fetch } from 'nitro/types';\nimport { fail } from './actions';\nimport { parseRequestData } from './parse-request-data';\nimport { validateWithSchema } from './validate';\n\ntype NodeContext = NonNullable<H3Event['node']>;\ntype OptionalSchema = StandardSchemaV1 | undefined;\ntype InferSchema<\n TSchema extends OptionalSchema,\n TFallback,\n> = TSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TSchema>\n : TFallback;\n\nexport interface DefineActionContext<\n TSchema extends OptionalSchema = undefined,\n TParamsSchema extends OptionalSchema = undefined,\n> {\n data: InferSchema<TSchema, Record<string, unknown>>;\n params: InferSchema<TParamsSchema, H3EventContext['params']>;\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n}\n\nexport interface DefineActionOptions<\n TSchema extends OptionalSchema = undefined,\n TParamsSchema extends OptionalSchema = undefined,\n> {\n schema?: TSchema;\n params?: TParamsSchema;\n handler: (\n context: DefineActionContext<TSchema, TParamsSchema>,\n ) => Promise<Response> | Response;\n}\n\n/**\n * Creates a server action handler with Standard Schema input validation.\n *\n * Parses the request body (JSON or FormData) and validates it against the\n * provided schema before invoking the handler. On validation failure,\n * returns `fail(422, issues)` with `StandardSchemaV1.Issue[]`.\n * Repeated form fields are preserved as arrays instead of being collapsed\n * to the last value.\n *\n * @example\n * ```typescript\n * import { defineAction, json } from '@analogjs/router/server/actions';\n * import * as v from 'valibot';\n *\n * const Schema = v.object({\n * email: v.pipe(v.string(), v.email()),\n * });\n *\n * export const action = defineAction({\n * schema: Schema,\n * handler: async ({ data }) => {\n * // data is typed as { email: string }\n * return json({ ok: true });\n * },\n * });\n * ```\n */\nexport function defineAction<\n TSchema extends OptionalSchema = undefined,\n TParamsSchema extends OptionalSchema = undefined,\n>(options: DefineActionOptions<TSchema, TParamsSchema>) {\n type Params = InferSchema<TParamsSchema, H3EventContext['params']>;\n\n function getParams(\n params: H3EventContext['params'],\n ): Params | Record<string, never> {\n return (params ?? {}) as Params | Record<string, never>;\n }\n\n return async (ctx: {\n params: H3EventContext['params'];\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n }): Promise<Response> => {\n const rawParams = getParams(ctx.params);\n\n if (options.params) {\n const paramsResult = await validateWithSchema(options.params, rawParams);\n if (paramsResult.issues) {\n return fail(422, paramsResult.issues);\n }\n return handleValidatedRequest(ctx, options, paramsResult.value as Params);\n }\n\n return handleValidatedRequest(ctx, options, rawParams as Params);\n };\n}\n\nasync function handleValidatedRequest<\n TSchema extends OptionalSchema = undefined,\n TParamsSchema extends OptionalSchema = undefined,\n>(\n ctx: {\n params: H3EventContext['params'];\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n },\n options: DefineActionOptions<TSchema, TParamsSchema>,\n params: InferSchema<TParamsSchema, H3EventContext['params']>,\n) {\n type Data = InferSchema<TSchema, Record<string, unknown>>;\n const body = await parseRequestData(ctx.event);\n\n let data: unknown = body;\n\n if (options.schema) {\n const result = await validateWithSchema(options.schema, body);\n if (result.issues) {\n return fail(422, result.issues);\n }\n data = result.value;\n }\n\n return options.handler({\n data: data as Data,\n params,\n req: ctx.req,\n res: ctx.res,\n fetch: ctx.fetch,\n event: ctx.event,\n });\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { H3Event } from 'nitro/h3';\nimport { getRequestURL } from 'nitro/h3';\nimport { fail, json } from './actions';\nimport { parseRequestData, parseSearchParams } from './parse-request-data';\nimport { validateWithSchema } from './validate';\n\nexport type DefineServerRouteResult = Response | unknown;\n\nexport interface ServerRouteHandler<\n TQuery = unknown,\n TBody = unknown,\n TResult = unknown,\n> {\n (event: H3Event): Promise<Response>;\n readonly _types: {\n readonly query: TQuery;\n readonly body: TBody;\n readonly result: TResult;\n };\n}\n\nexport type InferRouteQuery<T> =\n T extends ServerRouteHandler<infer Q, any, any> ? Q : never;\nexport type InferRouteBody<T> =\n T extends ServerRouteHandler<any, infer B, any> ? B : never;\nexport type InferRouteResult<T> =\n T extends ServerRouteHandler<any, any, infer R>\n ? Exclude<R, Response>\n : never;\n\ntype OptionalSchema = StandardSchemaV1 | undefined;\ntype InferSchema<\n TSchema extends OptionalSchema,\n TFallback = unknown,\n> = TSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TSchema>\n : TFallback;\ntype ResolveDataSchema<\n TInput extends OptionalSchema,\n TQuery extends OptionalSchema,\n TBody extends OptionalSchema,\n> = TInput extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TInput>\n : TQuery extends StandardSchemaV1\n ? TBody extends StandardSchemaV1\n ?\n | StandardSchemaV1.InferOutput<TQuery>\n | StandardSchemaV1.InferOutput<TBody>\n : StandardSchemaV1.InferOutput<TQuery>\n : TBody extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TBody>\n : unknown;\n\nexport interface DefineServerRouteContext<\n TInput extends StandardSchemaV1 | undefined = undefined,\n TQuery extends StandardSchemaV1 | undefined = undefined,\n TBody extends StandardSchemaV1 | undefined = undefined,\n TParams extends StandardSchemaV1 | undefined = undefined,\n> {\n data: ResolveDataSchema<TInput, TQuery, TBody>;\n query: InferSchema<TQuery, undefined>;\n body: InferSchema<TBody, undefined>;\n params: InferSchema<TParams, H3Event['context']['params']>;\n event: H3Event;\n}\n\nexport interface DefineServerRouteOptions<\n TInput extends StandardSchemaV1 | undefined = undefined,\n TOutput extends StandardSchemaV1 | undefined = undefined,\n TQuery extends StandardSchemaV1 | undefined = undefined,\n TBody extends StandardSchemaV1 | undefined = undefined,\n TParams extends StandardSchemaV1 | undefined = undefined,\n TResult extends DefineServerRouteResult = DefineServerRouteResult,\n> {\n input?: TInput;\n query?: TQuery;\n body?: TBody;\n params?: TParams;\n output?: TOutput;\n handler: (\n context: DefineServerRouteContext<TInput, TQuery, TBody, TParams>,\n ) => Promise<TResult> | TResult;\n}\n\nfunction isDevEnvironment() {\n return (\n typeof process !== 'undefined' &&\n (process.env['NODE_ENV'] === 'development' ||\n process.env['NODE_ENV'] === 'test')\n );\n}\n\nfunction warnOnOutputIssues(issues: ReadonlyArray<StandardSchemaV1.Issue>) {\n console.warn(\n `[analog] Server route output validation failed:\\n` +\n issues\n .map((i) => {\n const path = i.path\n ? ` at \"${i.path.map((p) => (typeof p === 'object' ? (p as { key: string }).key : p)).join('.')}\"`\n : '';\n return ` - ${i.message}${path}`;\n })\n .join('\\n'),\n );\n}\n\nfunction getRequestUrl(event: H3Event): string {\n try {\n return getRequestURL(event).href;\n } catch {\n return (event as H3Event & { request: Request }).request.url;\n }\n}\n\n/**\n * Creates an h3-compatible event handler with Standard Schema validation.\n *\n * - `input` schema validates the request body (POST/PUT/PATCH) or query\n * params (GET). Returns 422 with `StandardSchemaV1.Issue[]` on failure.\n * - `output` schema validates the response in development only (stripped\n * in production for zero overhead). Logs a warning on mismatch.\n * - Plain return values are serialized with `json(...)`; raw `Response`\n * objects are returned unchanged.\n *\n * @example\n * ```typescript\n * import { defineServerRoute } from '@analogjs/router/server/actions';\n * import * as v from 'valibot';\n *\n * const Input = v.object({\n * name: v.pipe(v.string(), v.minLength(1)),\n * email: v.pipe(v.string(), v.email()),\n * });\n * const Output = v.object({\n * id: v.string(),\n * name: v.string(),\n * });\n *\n * export default defineServerRoute({\n * input: Input,\n * output: Output,\n * handler: async ({ data }) => {\n * const user = await db.users.create(data);\n * return user;\n * },\n * });\n * ```\n */\nexport function defineServerRoute<\n TInput extends StandardSchemaV1 | undefined = undefined,\n TOutput extends StandardSchemaV1 | undefined = undefined,\n TQuery extends StandardSchemaV1 | undefined = undefined,\n TBody extends StandardSchemaV1 | undefined = undefined,\n TParams extends StandardSchemaV1 | undefined = undefined,\n TResult extends DefineServerRouteResult = DefineServerRouteResult,\n>(\n options: DefineServerRouteOptions<\n TInput,\n TOutput,\n TQuery,\n TBody,\n TParams,\n TResult\n >,\n): ServerRouteHandler<\n InferSchema<TQuery, undefined>,\n InferSchema<TBody, undefined>,\n TResult\n> {\n return (async (event: H3Event): Promise<Response> => {\n const method = event.method.toUpperCase();\n let data: unknown;\n let query: unknown;\n let body: unknown;\n let params: unknown = event.context?.params ?? {};\n\n if (options.params) {\n const paramsResult = await validateWithSchema(options.params, params);\n if (paramsResult.issues) {\n return fail(422, paramsResult.issues);\n }\n params = paramsResult.value;\n }\n\n if (options.input) {\n data = await parseRequestData(event);\n\n const inputResult = await validateWithSchema(options.input, data);\n if (inputResult.issues) {\n return fail(422, inputResult.issues);\n }\n data = inputResult.value;\n } else {\n if (options.query) {\n const url = new URL(getRequestUrl(event), 'http://localhost');\n const queryResult = await validateWithSchema(\n options.query,\n parseSearchParams(url.searchParams),\n );\n if (queryResult.issues) {\n return fail(422, queryResult.issues);\n }\n query = queryResult.value;\n }\n\n if (options.body && method !== 'GET' && method !== 'HEAD') {\n body = await parseRequestData(event);\n const bodyResult = await validateWithSchema(options.body, body);\n if (bodyResult.issues) {\n return fail(422, bodyResult.issues);\n }\n body = bodyResult.value;\n }\n\n if (method === 'GET' || method === 'HEAD') {\n data = query;\n } else if (body !== undefined) {\n data = body;\n } else {\n data = query;\n }\n }\n\n const result = await options.handler({\n data: data as ResolveDataSchema<TInput, TQuery, TBody>,\n query: query as InferSchema<TQuery, undefined>,\n body: body as InferSchema<TBody, undefined>,\n params: params as InferSchema<TParams, H3Event['context']['params']>,\n event,\n });\n\n if (result instanceof Response) {\n return result;\n }\n\n if (options.output && isDevEnvironment()) {\n const outputResult = await validateWithSchema(options.output, result);\n if (outputResult.issues) {\n warnOnOutputIssues(outputResult.issues);\n }\n }\n\n return json(result);\n }) as ServerRouteHandler<\n InferSchema<TQuery, undefined>,\n InferSchema<TBody, undefined>,\n TResult\n >;\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { H3Event, H3EventContext } from 'nitro/h3';\nimport { getRequestURL } from 'nitro/h3';\nimport type { $Fetch } from 'nitro/types';\nimport { fail } from './actions';\nimport { parseSearchParams } from './parse-request-data';\nimport { validateWithSchema } from './validate';\n\ntype NodeContext = NonNullable<H3Event['node']>;\ntype OptionalSchema = StandardSchemaV1 | undefined;\ntype InferSchema<\n TSchema extends OptionalSchema,\n TFallback,\n> = TSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TSchema>\n : TFallback;\n\nexport interface PageLoadContext<\n TParamsSchema extends OptionalSchema = undefined,\n TQuerySchema extends OptionalSchema = undefined,\n> {\n params: InferSchema<TParamsSchema, H3EventContext['params']>;\n query: InferSchema<\n TQuerySchema,\n Record<string, string | string[] | undefined>\n >;\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n}\n\nexport interface DefinePageLoadOptions<\n TParamsSchema extends OptionalSchema = undefined,\n TQuerySchema extends OptionalSchema = undefined,\n TResult = unknown,\n> {\n params?: TParamsSchema;\n query?: TQuerySchema;\n handler: (\n context: PageLoadContext<TParamsSchema, TQuerySchema>,\n ) => Promise<TResult> | TResult;\n}\n\n/**\n * Creates a typed page server load function with optional\n * Standard Schema validation for route params and query.\n *\n * Follows the same validation patterns as `defineAction` and\n * `defineServerRoute`: validates before invoking the handler,\n * returns `fail(422, issues)` on validation failure.\n *\n * @example\n * ```typescript\n * // src/app/pages/users/[id].server.ts\n * import { definePageLoad } from '@analogjs/router/server/actions';\n * import * as v from 'valibot';\n *\n * export const routeParamsSchema = v.object({\n * id: v.pipe(v.string(), v.regex(/^\\d+$/)),\n * });\n *\n * export const load = definePageLoad({\n * params: routeParamsSchema,\n * handler: async ({ params, fetch }) => {\n * // params.id is typed as string (validated)\n * const user = await fetch(`/api/users/${params.id}`);\n * return user;\n * },\n * });\n * ```\n */\nexport function definePageLoad<\n TParamsSchema extends OptionalSchema = undefined,\n TQuerySchema extends OptionalSchema = undefined,\n TResult = unknown,\n>(\n options: DefinePageLoadOptions<TParamsSchema, TQuerySchema, TResult>,\n): (ctx: {\n params: H3EventContext['params'];\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n}) => Promise<TResult | Response> {\n type Params = InferSchema<TParamsSchema, H3EventContext['params']>;\n type Query = InferSchema<\n TQuerySchema,\n Record<string, string | string[] | undefined>\n >;\n\n return async (ctx: {\n params: H3EventContext['params'];\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n }) => {\n let params: unknown = ctx.params ?? {};\n\n let requestUrl: string;\n try {\n requestUrl = getRequestURL(ctx.event).href;\n } catch {\n requestUrl = (ctx.event as H3Event & { request: Request }).request.url;\n }\n const url = new URL(requestUrl, 'http://localhost');\n let query: unknown = parseSearchParams(url.searchParams);\n\n // Validate params\n if (options.params) {\n const result = await validateWithSchema(options.params, params);\n if (result.issues) {\n return fail(422, result.issues);\n }\n params = result.value;\n }\n\n // Validate query\n if (options.query) {\n const result = await validateWithSchema(options.query, query);\n if (result.issues) {\n return fail(422, result.issues);\n }\n query = result.value;\n }\n\n return options.handler({\n params: params as Params,\n query: query as Query,\n req: ctx.req,\n res: ctx.res,\n fetch: ctx.fetch,\n event: ctx.event,\n });\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"analogjs-router-server-actions.mjs","names":[],"sources":["../../server/actions/src/actions.ts","../../server/actions/src/parse-request-data.ts","../../server/actions/src/validate.ts","../../server/actions/src/define-action.ts","../../server/actions/src/define-server-route.ts","../../server/actions/src/define-page-load.ts"],"sourcesContent":["import type { H3Event, H3EventContext } from 'nitro/h3';\nimport type { $Fetch } from 'nitro/types';\nimport type { NodeContext } from '../../../src/lib/route-types.js';\n\nexport type PageServerAction = {\n params: H3EventContext['params'];\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n};\n\nexport function fail<T = object>(status: number, errors: T): Response {\n return new Response(JSON.stringify(errors), {\n status,\n headers: {\n 'X-Analog-Errors': 'true',\n },\n });\n}\n\nexport function json<T = object>(data: T, config?: ResponseInit): Response {\n return new Response(JSON.stringify(data), {\n headers: {\n 'Content-Type': 'application/json; charset=utf-8',\n },\n ...config,\n });\n}\n\nexport function redirect(\n url: string,\n config: number | ResponseInit = 302,\n): Response {\n if (typeof config === 'number') {\n return new Response(null, {\n status: config,\n headers: {\n Location: `${url}`,\n },\n });\n }\n\n return new Response(null, {\n headers: {\n Location: `${url}`,\n },\n ...config,\n });\n}\n","import { readBody, readFormData, toRequest as h3ToRequest } from 'nitro/h3';\n\ntype RequestEntryValue = string | File;\ntype ParsedRequestValue = RequestEntryValue | RequestEntryValue[];\n\nfunction appendEntry(\n target: Record<string, ParsedRequestValue>,\n key: string,\n value: RequestEntryValue,\n) {\n const existingValue = target[key];\n\n if (existingValue === undefined) {\n target[key] = value;\n return;\n }\n\n if (Array.isArray(existingValue)) {\n existingValue.push(value);\n return;\n }\n\n target[key] = [existingValue, value];\n}\n\nfunction getRequest(event: { method: string; headers: Headers }): Request {\n const maybeRequest = (event as unknown as { request?: Request }).request;\n if (maybeRequest) {\n return maybeRequest;\n }\n return h3ToRequest(event as Parameters<typeof h3ToRequest>[0]);\n}\n\nfunction getContentType(event: { method: string; headers: Headers }): string {\n const request = getRequest(event);\n\n return (\n request.headers.get('content-type') ??\n event.headers.get('content-type') ??\n event.headers.get('Content-Type') ??\n ''\n );\n}\n\nfunction isJsonContentType(contentType: string): boolean {\n const mimeType = contentType.split(';', 1)[0]?.trim().toLowerCase() ?? '';\n return mimeType === 'application/json' || mimeType.endsWith('+json');\n}\n\nfunction isFormContentType(contentType: string): boolean {\n return (\n contentType.includes('multipart/form-data') ||\n contentType.includes('application/x-www-form-urlencoded')\n );\n}\n\nexport function parseSearchParams(\n searchParams: URLSearchParams,\n): Record<string, ParsedRequestValue> {\n const result: Record<string, ParsedRequestValue> = {};\n searchParams.forEach((value, key) => {\n appendEntry(result, key, value);\n });\n return result;\n}\n\nexport function parseFormData(\n formData: FormData,\n): Record<string, ParsedRequestValue> {\n const result: Record<string, ParsedRequestValue> = {};\n formData.forEach((value, key) => {\n appendEntry(result, key, value as RequestEntryValue);\n });\n return result;\n}\n\nexport async function parseRequestData(event: {\n method: string;\n headers: Headers;\n}): Promise<unknown> {\n const request = getRequest(event);\n const httpEvent = event as unknown as Parameters<typeof readBody>[0];\n const h3Event = event as unknown as Parameters<typeof readFormData>[0];\n const method = event.method.toUpperCase();\n\n if (method === 'GET' || method === 'HEAD') {\n const url = new URL(request.url, 'http://localhost');\n return parseSearchParams(url.searchParams);\n }\n\n const contentType = getContentType(event);\n\n if (isJsonContentType(contentType)) {\n try {\n return (await readBody(httpEvent)) ?? {};\n } catch {\n try {\n return await request.json();\n } catch {\n return {};\n }\n }\n }\n\n if (isFormContentType(contentType)) {\n try {\n return parseFormData(await readFormData(h3Event));\n } catch {\n if (typeof request.formData === 'function') {\n return parseFormData(await request.formData());\n }\n\n return {};\n }\n }\n\n try {\n return (await readBody(httpEvent)) ?? {};\n } catch {\n try {\n return await request.json();\n } catch {\n return {};\n }\n }\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\n\n/**\n * Validates unknown input against a Standard Schema.\n *\n * Handles both sync and async `validate` implementations — the Standard\n * Schema spec allows either return shape.\n */\nexport async function validateWithSchema<T extends StandardSchemaV1>(\n schema: T,\n data: unknown,\n): Promise<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<T>>> {\n return schema['~standard'].validate(data);\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { H3Event, H3EventContext } from 'nitro/h3';\nimport type { $Fetch } from 'nitro/types';\nimport { fail } from './actions';\nimport { parseRequestData } from './parse-request-data';\nimport { validateWithSchema } from './validate';\n\ntype NodeContext = NonNullable<H3Event['node']>;\ntype OptionalSchema = StandardSchemaV1 | undefined;\ntype InferSchema<\n TSchema extends OptionalSchema,\n TFallback,\n> = TSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TSchema>\n : TFallback;\n\nexport interface DefineActionContext<\n TSchema extends OptionalSchema = undefined,\n TParamsSchema extends OptionalSchema = undefined,\n> {\n data: InferSchema<TSchema, Record<string, unknown>>;\n params: InferSchema<TParamsSchema, H3EventContext['params']>;\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n}\n\nexport interface DefineActionOptions<\n TSchema extends OptionalSchema = undefined,\n TParamsSchema extends OptionalSchema = undefined,\n> {\n schema?: TSchema;\n params?: TParamsSchema;\n handler: (\n context: DefineActionContext<TSchema, TParamsSchema>,\n ) => Promise<Response> | Response;\n}\n\n/**\n * Creates a server action handler with Standard Schema input validation.\n *\n * Parses the request body (JSON or FormData) and validates it against the\n * provided schema before invoking the handler. On validation failure,\n * returns `fail(422, issues)` with `StandardSchemaV1.Issue[]`.\n * Repeated form fields are preserved as arrays instead of being collapsed\n * to the last value.\n *\n * @example\n * ```typescript\n * import { defineAction, json } from '@analogjs/router/server/actions';\n * import * as v from 'valibot';\n *\n * const Schema = v.object({\n * email: v.pipe(v.string(), v.email()),\n * });\n *\n * export const action = defineAction({\n * schema: Schema,\n * handler: async ({ data }) => {\n * // data is typed as { email: string }\n * return json({ ok: true });\n * },\n * });\n * ```\n */\nexport function defineAction<\n TSchema extends OptionalSchema = undefined,\n TParamsSchema extends OptionalSchema = undefined,\n>(options: DefineActionOptions<TSchema, TParamsSchema>) {\n type Params = InferSchema<TParamsSchema, H3EventContext['params']>;\n\n function getParams(\n params: H3EventContext['params'],\n ): Params | Record<string, never> {\n return (params ?? {}) as Params | Record<string, never>;\n }\n\n return async (ctx: {\n params: H3EventContext['params'];\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n }): Promise<Response> => {\n const rawParams = getParams(ctx.params);\n\n if (options.params) {\n const paramsResult = await validateWithSchema(options.params, rawParams);\n if (paramsResult.issues) {\n return fail(422, paramsResult.issues);\n }\n return handleValidatedRequest(ctx, options, paramsResult.value as Params);\n }\n\n return handleValidatedRequest(ctx, options, rawParams as Params);\n };\n}\n\nasync function handleValidatedRequest<\n TSchema extends OptionalSchema = undefined,\n TParamsSchema extends OptionalSchema = undefined,\n>(\n ctx: {\n params: H3EventContext['params'];\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n },\n options: DefineActionOptions<TSchema, TParamsSchema>,\n params: InferSchema<TParamsSchema, H3EventContext['params']>,\n) {\n type Data = InferSchema<TSchema, Record<string, unknown>>;\n const body = await parseRequestData(ctx.event);\n\n let data: unknown = body;\n\n if (options.schema) {\n const result = await validateWithSchema(options.schema, body);\n if (result.issues) {\n return fail(422, result.issues);\n }\n data = result.value;\n }\n\n return options.handler({\n data: data as Data,\n params,\n req: ctx.req,\n res: ctx.res,\n fetch: ctx.fetch,\n event: ctx.event,\n });\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { H3Event } from 'nitro/h3';\nimport { getRequestURL } from 'nitro/h3';\nimport { fail, json } from './actions';\nimport { parseRequestData, parseSearchParams } from './parse-request-data';\nimport { validateWithSchema } from './validate';\n\nexport type DefineServerRouteResult = Response | unknown;\n\nexport interface ServerRouteHandler<\n TQuery = unknown,\n TBody = unknown,\n TResult = unknown,\n> {\n (event: H3Event): Promise<Response>;\n readonly _types: {\n readonly query: TQuery;\n readonly body: TBody;\n readonly result: TResult;\n };\n}\n\nexport type InferRouteQuery<T> =\n T extends ServerRouteHandler<infer Q, any, any> ? Q : never;\nexport type InferRouteBody<T> =\n T extends ServerRouteHandler<any, infer B, any> ? B : never;\nexport type InferRouteResult<T> =\n T extends ServerRouteHandler<any, any, infer R>\n ? Exclude<R, Response>\n : never;\n\ntype OptionalSchema = StandardSchemaV1 | undefined;\ntype InferSchema<\n TSchema extends OptionalSchema,\n TFallback = unknown,\n> = TSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TSchema>\n : TFallback;\ntype ResolveDataSchema<\n TInput extends OptionalSchema,\n TQuery extends OptionalSchema,\n TBody extends OptionalSchema,\n> = TInput extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TInput>\n : TQuery extends StandardSchemaV1\n ? TBody extends StandardSchemaV1\n ?\n | StandardSchemaV1.InferOutput<TQuery>\n | StandardSchemaV1.InferOutput<TBody>\n : StandardSchemaV1.InferOutput<TQuery>\n : TBody extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TBody>\n : unknown;\n\nexport interface DefineServerRouteContext<\n TInput extends StandardSchemaV1 | undefined = undefined,\n TQuery extends StandardSchemaV1 | undefined = undefined,\n TBody extends StandardSchemaV1 | undefined = undefined,\n TParams extends StandardSchemaV1 | undefined = undefined,\n> {\n data: ResolveDataSchema<TInput, TQuery, TBody>;\n query: InferSchema<TQuery, undefined>;\n body: InferSchema<TBody, undefined>;\n params: InferSchema<TParams, H3Event['context']['params']>;\n event: H3Event;\n}\n\nexport interface DefineServerRouteOptions<\n TInput extends StandardSchemaV1 | undefined = undefined,\n TOutput extends StandardSchemaV1 | undefined = undefined,\n TQuery extends StandardSchemaV1 | undefined = undefined,\n TBody extends StandardSchemaV1 | undefined = undefined,\n TParams extends StandardSchemaV1 | undefined = undefined,\n TResult extends DefineServerRouteResult = DefineServerRouteResult,\n> {\n input?: TInput;\n query?: TQuery;\n body?: TBody;\n params?: TParams;\n output?: TOutput;\n handler: (\n context: DefineServerRouteContext<TInput, TQuery, TBody, TParams>,\n ) => Promise<TResult> | TResult;\n}\n\nfunction isDevEnvironment() {\n return (\n typeof process !== 'undefined' &&\n (process.env['NODE_ENV'] === 'development' ||\n process.env['NODE_ENV'] === 'test')\n );\n}\n\nfunction warnOnOutputIssues(issues: ReadonlyArray<StandardSchemaV1.Issue>) {\n console.warn(\n `[analog] Server route output validation failed:\\n` +\n issues\n .map((i) => {\n const path = i.path\n ? ` at \"${i.path.map((p) => (typeof p === 'object' ? (p as { key: string }).key : p)).join('.')}\"`\n : '';\n return ` - ${i.message}${path}`;\n })\n .join('\\n'),\n );\n}\n\nfunction getRequestUrl(event: H3Event): string {\n try {\n return getRequestURL(event).href;\n } catch {\n return (event as H3Event & { request: Request }).request.url;\n }\n}\n\n/**\n * Creates an h3-compatible event handler with Standard Schema validation.\n *\n * - `input` schema validates the request body (POST/PUT/PATCH) or query\n * params (GET). Returns 422 with `StandardSchemaV1.Issue[]` on failure.\n * - `output` schema validates the response in development only (stripped\n * in production for zero overhead). Logs a warning on mismatch.\n * - Plain return values are serialized with `json(...)`; raw `Response`\n * objects are returned unchanged.\n *\n * @example\n * ```typescript\n * import { defineServerRoute } from '@analogjs/router/server/actions';\n * import * as v from 'valibot';\n *\n * const Input = v.object({\n * name: v.pipe(v.string(), v.minLength(1)),\n * email: v.pipe(v.string(), v.email()),\n * });\n * const Output = v.object({\n * id: v.string(),\n * name: v.string(),\n * });\n *\n * export default defineServerRoute({\n * input: Input,\n * output: Output,\n * handler: async ({ data }) => {\n * const user = await db.users.create(data);\n * return user;\n * },\n * });\n * ```\n */\nexport function defineServerRoute<\n TInput extends StandardSchemaV1 | undefined = undefined,\n TOutput extends StandardSchemaV1 | undefined = undefined,\n TQuery extends StandardSchemaV1 | undefined = undefined,\n TBody extends StandardSchemaV1 | undefined = undefined,\n TParams extends StandardSchemaV1 | undefined = undefined,\n TResult extends DefineServerRouteResult = DefineServerRouteResult,\n>(\n options: DefineServerRouteOptions<\n TInput,\n TOutput,\n TQuery,\n TBody,\n TParams,\n TResult\n >,\n): ServerRouteHandler<\n InferSchema<TQuery, undefined>,\n InferSchema<TBody, undefined>,\n TResult\n> {\n return (async (event: H3Event): Promise<Response> => {\n const method = event.method.toUpperCase();\n let data: unknown;\n let query: unknown;\n let body: unknown;\n let params: unknown = event.context?.params ?? {};\n\n if (options.params) {\n const paramsResult = await validateWithSchema(options.params, params);\n if (paramsResult.issues) {\n return fail(422, paramsResult.issues);\n }\n params = paramsResult.value;\n }\n\n if (options.input) {\n data = await parseRequestData(event);\n\n const inputResult = await validateWithSchema(options.input, data);\n if (inputResult.issues) {\n return fail(422, inputResult.issues);\n }\n data = inputResult.value;\n } else {\n if (options.query) {\n const url = new URL(getRequestUrl(event), 'http://localhost');\n const queryResult = await validateWithSchema(\n options.query,\n parseSearchParams(url.searchParams),\n );\n if (queryResult.issues) {\n return fail(422, queryResult.issues);\n }\n query = queryResult.value;\n }\n\n if (options.body && method !== 'GET' && method !== 'HEAD') {\n body = await parseRequestData(event);\n const bodyResult = await validateWithSchema(options.body, body);\n if (bodyResult.issues) {\n return fail(422, bodyResult.issues);\n }\n body = bodyResult.value;\n }\n\n if (method === 'GET' || method === 'HEAD') {\n data = query;\n } else if (body !== undefined) {\n data = body;\n } else {\n data = query;\n }\n }\n\n const result = await options.handler({\n data: data as ResolveDataSchema<TInput, TQuery, TBody>,\n query: query as InferSchema<TQuery, undefined>,\n body: body as InferSchema<TBody, undefined>,\n params: params as InferSchema<TParams, H3Event['context']['params']>,\n event,\n });\n\n if (result instanceof Response) {\n return result;\n }\n\n if (options.output && isDevEnvironment()) {\n const outputResult = await validateWithSchema(options.output, result);\n if (outputResult.issues) {\n warnOnOutputIssues(outputResult.issues);\n }\n }\n\n return json(result);\n }) as ServerRouteHandler<\n InferSchema<TQuery, undefined>,\n InferSchema<TBody, undefined>,\n TResult\n >;\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { H3Event, H3EventContext } from 'nitro/h3';\nimport { getRequestURL } from 'nitro/h3';\nimport type { $Fetch } from 'nitro/types';\nimport { fail } from './actions';\nimport { parseSearchParams } from './parse-request-data';\nimport { validateWithSchema } from './validate';\n\ntype NodeContext = NonNullable<H3Event['node']>;\ntype OptionalSchema = StandardSchemaV1 | undefined;\ntype InferSchema<\n TSchema extends OptionalSchema,\n TFallback,\n> = TSchema extends StandardSchemaV1\n ? StandardSchemaV1.InferOutput<TSchema>\n : TFallback;\n\nexport interface PageLoadContext<\n TParamsSchema extends OptionalSchema = undefined,\n TQuerySchema extends OptionalSchema = undefined,\n> {\n params: InferSchema<TParamsSchema, H3EventContext['params']>;\n query: InferSchema<\n TQuerySchema,\n Record<string, string | string[] | undefined>\n >;\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n}\n\nexport interface DefinePageLoadOptions<\n TParamsSchema extends OptionalSchema = undefined,\n TQuerySchema extends OptionalSchema = undefined,\n TResult = unknown,\n> {\n params?: TParamsSchema;\n query?: TQuerySchema;\n handler: (\n context: PageLoadContext<TParamsSchema, TQuerySchema>,\n ) => Promise<TResult> | TResult;\n}\n\n/**\n * Creates a typed page server load function with optional\n * Standard Schema validation for route params and query.\n *\n * Follows the same validation patterns as `defineAction` and\n * `defineServerRoute`: validates before invoking the handler,\n * returns `fail(422, issues)` on validation failure.\n *\n * @example\n * ```typescript\n * // src/app/pages/users/[id].server.ts\n * import { definePageLoad } from '@analogjs/router/server/actions';\n * import * as v from 'valibot';\n *\n * export const routeParamsSchema = v.object({\n * id: v.pipe(v.string(), v.regex(/^\\d+$/)),\n * });\n *\n * export const load = definePageLoad({\n * params: routeParamsSchema,\n * handler: async ({ params, fetch }) => {\n * // params.id is typed as string (validated)\n * const user = await fetch(`/api/users/${params.id}`);\n * return user;\n * },\n * });\n * ```\n */\nexport function definePageLoad<\n TParamsSchema extends OptionalSchema = undefined,\n TQuerySchema extends OptionalSchema = undefined,\n TResult = unknown,\n>(\n options: DefinePageLoadOptions<TParamsSchema, TQuerySchema, TResult>,\n): (ctx: {\n params: H3EventContext['params'];\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n}) => Promise<TResult | Response> {\n type Params = InferSchema<TParamsSchema, H3EventContext['params']>;\n type Query = InferSchema<\n TQuerySchema,\n Record<string, string | string[] | undefined>\n >;\n\n return async (ctx: {\n params: H3EventContext['params'];\n req: NodeContext['req'];\n res: NonNullable<NodeContext['res']>;\n fetch: $Fetch;\n event: H3Event;\n }) => {\n let params: unknown = ctx.params ?? {};\n\n let requestUrl: string;\n try {\n requestUrl = getRequestURL(ctx.event).href;\n } catch {\n requestUrl = (ctx.event as H3Event & { request: Request }).request.url;\n }\n const url = new URL(requestUrl, 'http://localhost');\n let query: unknown = parseSearchParams(url.searchParams);\n\n // Validate params\n if (options.params) {\n const result = await validateWithSchema(options.params, params);\n if (result.issues) {\n return fail(422, result.issues);\n }\n params = result.value;\n }\n\n // Validate query\n if (options.query) {\n const result = await validateWithSchema(options.query, query);\n if (result.issues) {\n return fail(422, result.issues);\n }\n query = result.value;\n }\n\n return options.handler({\n params: params as Params,\n query: query as Query,\n req: ctx.req,\n res: ctx.res,\n fetch: ctx.fetch,\n event: ctx.event,\n });\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analogjs-router-server.mjs","names":[],"sources":["../../../../packages/router/server/src/provide-server-context.ts","../../../../packages/router/server/src/tokens.ts","../../../../packages/router/server/src/server-component-render.ts","../../../../packages/router/server/src/render.ts"],"sourcesContent":["import { StaticProvider, ɵresetCompiledComponents } from '@angular/core';\nimport { ɵSERVER_CONTEXT as SERVER_CONTEXT } from '@angular/platform-server';\n\nimport {\n BASE_URL,\n INTERNAL_FETCH,\n REQUEST,\n RESPONSE,\n ServerInternalFetch,\n ServerRequest,\n ServerResponse,\n} from '@analogjs/router/tokens';\n\nfunction getHeaderValue(\n value: string | string[] | undefined,\n): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction getRequestHeader(\n req: ServerRequest,\n name: string,\n): string | undefined {\n const headers = (req as { headers?: unknown }).headers;\n\n if (!headers) {\n return undefined;\n }\n\n if (\n typeof headers === 'object' &&\n headers !== null &&\n 'get' in headers &&\n typeof headers.get === 'function'\n ) {\n return headers.get(name) ?? undefined;\n }\n\n return getHeaderValue(\n (headers as Record<string, string | string[] | undefined>)[name],\n );\n}\n\nexport function provideServerContext({\n req,\n res,\n fetch,\n}: {\n req: ServerRequest;\n res: ServerResponse;\n fetch?: ServerInternalFetch;\n}): StaticProvider[] {\n const baseUrl = getBaseUrl(req);\n\n if (import.meta.env.DEV) {\n ɵresetCompiledComponents();\n }\n\n return [\n { provide: SERVER_CONTEXT, useValue: 'ssr-analog' },\n { provide: REQUEST, useValue: req },\n { provide: RESPONSE, useValue: res },\n { provide: BASE_URL, useValue: baseUrl },\n { provide: INTERNAL_FETCH, useValue: fetch },\n ];\n}\n\nexport function getBaseUrl(req: ServerRequest): string {\n const protocol = getRequestProtocol(req);\n const host =\n getRequestHeader(req, 'x-forwarded-host') ??\n getRequestHeader(req, 'host') ??\n 'localhost';\n const originalUrl = req.originalUrl || req.url || '/';\n const parsedUrl = new URL(\n '',\n `${protocol}://${host}${\n originalUrl.endsWith('/')\n ? originalUrl.substring(0, originalUrl.length - 1)\n : originalUrl\n }`,\n );\n const baseUrl = parsedUrl.origin;\n\n return baseUrl;\n}\n\nexport function getRequestProtocol(\n req: ServerRequest,\n opts: { xForwardedProto?: boolean } = {},\n): string {\n const forwardedProto = getRequestHeader(req, 'x-forwarded-proto')\n ?.split(',')[0]\n ?.trim();\n\n if (opts.xForwardedProto !== false && forwardedProto === 'https') {\n return 'https';\n }\n\n return (req.connection as any)?.encrypted ? 'https' : 'http';\n}\n","import {\n assertInInjectionContext,\n inject,\n InjectionToken,\n makeStateKey,\n Provider,\n TransferState,\n} from '@angular/core';\n\nexport const STATIC_PROPS: InjectionToken<Record<string, any>> =\n new InjectionToken<Record<string, any>>('Static Props');\n\nexport function provideStaticProps<T = Record<string, any>>(\n props: T,\n): Provider {\n return {\n provide: STATIC_PROPS,\n useFactory() {\n return props;\n },\n };\n}\n\nexport function injectStaticProps(): Record<string, any> {\n assertInInjectionContext(injectStaticProps);\n\n return inject(STATIC_PROPS);\n}\n\nexport function injectStaticOutputs<T>(): { set(data: T): void } {\n const transferState = inject(TransferState);\n const outputsKey = makeStateKey<T>('_analog_output');\n\n return {\n set(data: T): void {\n transferState.set(outputsKey, data);\n },\n };\n}\n","import { ApplicationConfig, Type } from '@angular/core';\nimport {\n bootstrapApplication,\n type BootstrapContext,\n} from '@angular/platform-browser';\nimport {\n reflectComponentType,\n ɵConsole as Console,\n APP_ID,\n} from '@angular/core';\nimport {\n provideServerRendering,\n renderApplication,\n ɵSERVER_CONTEXT as SERVER_CONTEXT,\n} from '@angular/platform-server';\nimport { ServerContext } from '@analogjs/router/tokens';\nimport { json as readJsonStream } from 'node:stream/consumers';\n\nimport { provideStaticProps } from './tokens';\n\ntype ComponentLoader = () => Promise<Type<unknown>>;\n\nexport function serverComponentRequest(\n serverContext: ServerContext,\n): string | undefined {\n // `ServerContext` is still backed by raw Node req/res, so read the header\n // directly instead of reconstructing an H3Event just for lookup.\n // In h3 v2 / Nitro v3, req may be undefined during fetch-based prerendering\n // (where event.node is not populated), so guard with optional chaining.\n const serverComponentId = serverContext.req?.headers?.[\n 'x-analog-component'\n ] as string | undefined;\n\n if (\n !serverComponentId &&\n serverContext.req?.url &&\n serverContext.req.url.startsWith('/_analog/components')\n ) {\n const componentId = serverContext.req.url.split('/')?.[3];\n\n return componentId;\n }\n\n return serverComponentId;\n}\n\nconst components = import.meta.glob([\n '/src/server/components/**/*.{ts,analog,ag}',\n]);\n\nexport async function renderServerComponent(\n url: string,\n serverContext: ServerContext,\n config?: ApplicationConfig,\n): Promise<Response> {\n const componentReqId = serverComponentRequest(serverContext) as string;\n const { componentLoader, componentId } = getComponentLoader(componentReqId);\n\n if (!componentLoader) {\n return new Response(`Server Component Not Found ${componentId}`, {\n status: 404,\n });\n }\n\n const component = ((await componentLoader()) as any)[\n 'default'\n ] as Type<unknown>;\n\n if (!component) {\n return new Response(`No default export for ${componentId}`, {\n status: 422,\n });\n }\n\n const mirror = reflectComponentType(component);\n const selector = mirror?.selector.split(',')?.[0] || 'server-component';\n // Server component requests POST JSON props from the client bridge, so parse\n // the Node request body directly instead of rebuilding an H3Event wrapper.\n const body =\n (await readJsonStream(serverContext.req).catch(() => ({}))) || {};\n const appId = `analog-server-${selector.toLowerCase()}-${new Date().getTime()}`;\n\n const bootstrap = (context?: BootstrapContext) =>\n bootstrapApplication(\n component,\n {\n providers: [\n provideServerRendering(),\n provideStaticProps(body),\n { provide: SERVER_CONTEXT, useValue: 'analog-server-component' },\n {\n provide: APP_ID,\n useFactory() {\n return appId;\n },\n },\n ...(config?.providers || []),\n ],\n },\n context,\n );\n\n const html = await renderApplication(bootstrap, {\n url,\n document: `<${selector}></${selector}>`,\n platformProviders: [\n {\n provide: Console,\n useFactory() {\n return {\n warn: () => {\n /* noop */\n },\n log: () => {\n /* noop */\n },\n };\n },\n },\n ],\n });\n\n const outputs = retrieveTransferredState(html, appId);\n const responseData: { html: string; outputs: Record<string, any> } = {\n html,\n outputs,\n };\n\n return new Response(JSON.stringify(responseData), {\n headers: {\n 'X-Analog-Component': 'true',\n },\n });\n}\n\nfunction getComponentLoader(componentReqId: string): {\n componentLoader: ComponentLoader | undefined;\n componentId: string;\n} {\n const _componentId = `/src/server/components/${componentReqId.toLowerCase()}`;\n let componentLoader: ComponentLoader | undefined = undefined;\n let componentId = _componentId;\n\n if (components[`${_componentId}.ts`]) {\n componentId = `${_componentId}.ts`;\n componentLoader = components[componentId] as ComponentLoader;\n }\n\n return { componentLoader, componentId };\n}\n\nfunction retrieveTransferredState(\n html: string,\n appId: string,\n): Record<string, unknown | undefined> {\n const regex = new RegExp(\n `<script id=\"${appId}-state\" type=\"application/json\">(.*?)</script>`,\n );\n const match = html.match(regex);\n\n if (match) {\n const scriptContent = match[1];\n\n if (scriptContent) {\n try {\n const parsedContent: {\n _analog_output: Record<string, unknown | undefined>;\n } = JSON.parse(scriptContent);\n return parsedContent._analog_output || {};\n } catch (e) {\n console.warn('Exception while parsing static outputs for ' + appId, e);\n }\n }\n\n return {};\n } else {\n return {};\n }\n}\n","import {\n ApplicationConfig,\n Provider,\n Type,\n enableProdMode,\n} from '@angular/core';\nimport {\n bootstrapApplication,\n type BootstrapContext,\n} from '@angular/platform-browser';\nimport { renderApplication } from '@angular/platform-server';\nimport type { ServerContext } from '@analogjs/router/tokens';\n\nimport { provideServerContext } from './provide-server-context';\nimport {\n serverComponentRequest,\n renderServerComponent,\n} from './server-component-render';\n\nif (import.meta.env.PROD) {\n enableProdMode();\n}\n\n/**\n * Returns a function that accepts the navigation URL,\n * the root HTML, and server context.\n *\n * @param rootComponent\n * @param config\n * @param platformProviders\n * @returns Promise<string | Reponse>\n */\nexport function render(\n rootComponent: Type<unknown>,\n config: ApplicationConfig,\n platformProviders: Provider[] = [],\n) {\n function bootstrap(context?: BootstrapContext) {\n return bootstrapApplication(rootComponent, config, context);\n }\n\n return async function render(\n url: string,\n document: string,\n serverContext: ServerContext,\n ): Promise<string | Response> {\n if (serverComponentRequest(serverContext)) {\n return await renderServerComponent(url, serverContext);\n }\n\n const html = await renderApplication(bootstrap, {\n document,\n url,\n platformProviders: [\n provideServerContext(serverContext),\n platformProviders,\n ],\n });\n\n return html;\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"analogjs-router-server.mjs","names":[],"sources":["../../server/src/provide-server-context.ts","../../server/src/tokens.ts","../../server/src/server-component-render.ts","../../server/src/render.ts"],"sourcesContent":["import { StaticProvider, ɵresetCompiledComponents } from '@angular/core';\nimport { ɵSERVER_CONTEXT as SERVER_CONTEXT } from '@angular/platform-server';\n\nimport {\n BASE_URL,\n INTERNAL_FETCH,\n REQUEST,\n RESPONSE,\n ServerInternalFetch,\n ServerRequest,\n ServerResponse,\n} from '@analogjs/router/tokens';\n\nfunction getHeaderValue(\n value: string | string[] | undefined,\n): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction getRequestHeader(\n req: ServerRequest,\n name: string,\n): string | undefined {\n const headers = (req as { headers?: unknown }).headers;\n\n if (!headers) {\n return undefined;\n }\n\n if (\n typeof headers === 'object' &&\n headers !== null &&\n 'get' in headers &&\n typeof headers.get === 'function'\n ) {\n return headers.get(name) ?? undefined;\n }\n\n return getHeaderValue(\n (headers as Record<string, string | string[] | undefined>)[name],\n );\n}\n\nexport function provideServerContext({\n req,\n res,\n fetch,\n}: {\n req: ServerRequest;\n res: ServerResponse;\n fetch?: ServerInternalFetch;\n}): StaticProvider[] {\n const baseUrl = getBaseUrl(req);\n\n if (import.meta.env.DEV) {\n ɵresetCompiledComponents();\n }\n\n return [\n { provide: SERVER_CONTEXT, useValue: 'ssr-analog' },\n { provide: REQUEST, useValue: req },\n { provide: RESPONSE, useValue: res },\n { provide: BASE_URL, useValue: baseUrl },\n { provide: INTERNAL_FETCH, useValue: fetch },\n ];\n}\n\nexport function getBaseUrl(req: ServerRequest): string {\n const protocol = getRequestProtocol(req);\n const host =\n getRequestHeader(req, 'x-forwarded-host') ??\n getRequestHeader(req, 'host') ??\n 'localhost';\n const originalUrl = req.originalUrl || req.url || '/';\n const parsedUrl = new URL(\n '',\n `${protocol}://${host}${\n originalUrl.endsWith('/')\n ? originalUrl.substring(0, originalUrl.length - 1)\n : originalUrl\n }`,\n );\n const baseUrl = parsedUrl.origin;\n\n return baseUrl;\n}\n\nexport function getRequestProtocol(\n req: ServerRequest,\n opts: { xForwardedProto?: boolean } = {},\n): string {\n const forwardedProto = getRequestHeader(req, 'x-forwarded-proto')\n ?.split(',')[0]\n ?.trim();\n\n if (opts.xForwardedProto !== false && forwardedProto === 'https') {\n return 'https';\n }\n\n return (req.connection as any)?.encrypted ? 'https' : 'http';\n}\n","import {\n assertInInjectionContext,\n inject,\n InjectionToken,\n makeStateKey,\n Provider,\n TransferState,\n} from '@angular/core';\n\nexport const STATIC_PROPS: InjectionToken<Record<string, any>> =\n new InjectionToken<Record<string, any>>('Static Props');\n\nexport function provideStaticProps<T = Record<string, any>>(\n props: T,\n): Provider {\n return {\n provide: STATIC_PROPS,\n useFactory() {\n return props;\n },\n };\n}\n\nexport function injectStaticProps(): Record<string, any> {\n assertInInjectionContext(injectStaticProps);\n\n return inject(STATIC_PROPS);\n}\n\nexport function injectStaticOutputs<T>(): { set(data: T): void } {\n const transferState = inject(TransferState);\n const outputsKey = makeStateKey<T>('_analog_output');\n\n return {\n set(data: T): void {\n transferState.set(outputsKey, data);\n },\n };\n}\n","import { ApplicationConfig, Type } from '@angular/core';\nimport {\n bootstrapApplication,\n type BootstrapContext,\n} from '@angular/platform-browser';\nimport {\n reflectComponentType,\n ɵConsole as Console,\n APP_ID,\n} from '@angular/core';\nimport {\n provideServerRendering,\n renderApplication,\n ɵSERVER_CONTEXT as SERVER_CONTEXT,\n} from '@angular/platform-server';\nimport { ServerContext } from '@analogjs/router/tokens';\nimport { json as readJsonStream } from 'node:stream/consumers';\n\nimport { provideStaticProps } from './tokens';\n\ntype ComponentLoader = () => Promise<Type<unknown>>;\n\nexport function serverComponentRequest(\n serverContext: ServerContext,\n): string | undefined {\n // `ServerContext` is still backed by raw Node req/res, so read the header\n // directly instead of reconstructing an H3Event just for lookup.\n // In h3 v2 / Nitro v3, req may be undefined during fetch-based prerendering\n // (where event.node is not populated), so guard with optional chaining.\n const serverComponentId = serverContext.req?.headers?.[\n 'x-analog-component'\n ] as string | undefined;\n\n if (\n !serverComponentId &&\n serverContext.req?.url &&\n serverContext.req.url.startsWith('/_analog/components')\n ) {\n const componentId = serverContext.req.url.split('/')?.[3];\n\n return componentId;\n }\n\n return serverComponentId;\n}\n\nconst components = import.meta.glob([\n '/src/server/components/**/*.{ts,analog,ag}',\n]);\n\nexport async function renderServerComponent(\n url: string,\n serverContext: ServerContext,\n config?: ApplicationConfig,\n): Promise<Response> {\n const componentReqId = serverComponentRequest(serverContext) as string;\n const { componentLoader, componentId } = getComponentLoader(componentReqId);\n\n if (!componentLoader) {\n return new Response(`Server Component Not Found ${componentId}`, {\n status: 404,\n });\n }\n\n const component = ((await componentLoader()) as any)[\n 'default'\n ] as Type<unknown>;\n\n if (!component) {\n return new Response(`No default export for ${componentId}`, {\n status: 422,\n });\n }\n\n const mirror = reflectComponentType(component);\n const selector = mirror?.selector.split(',')?.[0] || 'server-component';\n // Server component requests POST JSON props from the client bridge, so parse\n // the Node request body directly instead of rebuilding an H3Event wrapper.\n const body =\n (await readJsonStream(serverContext.req).catch(() => ({}))) || {};\n const appId = `analog-server-${selector.toLowerCase()}-${new Date().getTime()}`;\n\n const bootstrap = (context?: BootstrapContext) =>\n bootstrapApplication(\n component,\n {\n providers: [\n provideServerRendering(),\n provideStaticProps(body),\n { provide: SERVER_CONTEXT, useValue: 'analog-server-component' },\n {\n provide: APP_ID,\n useFactory() {\n return appId;\n },\n },\n ...(config?.providers || []),\n ],\n },\n context,\n );\n\n const html = await renderApplication(bootstrap, {\n url,\n document: `<${selector}></${selector}>`,\n platformProviders: [\n {\n provide: Console,\n useFactory() {\n return {\n warn: () => {\n /* noop */\n },\n log: () => {\n /* noop */\n },\n };\n },\n },\n ],\n });\n\n const outputs = retrieveTransferredState(html, appId);\n const responseData: { html: string; outputs: Record<string, any> } = {\n html,\n outputs,\n };\n\n return new Response(JSON.stringify(responseData), {\n headers: {\n 'X-Analog-Component': 'true',\n },\n });\n}\n\nfunction getComponentLoader(componentReqId: string): {\n componentLoader: ComponentLoader | undefined;\n componentId: string;\n} {\n const _componentId = `/src/server/components/${componentReqId.toLowerCase()}`;\n let componentLoader: ComponentLoader | undefined = undefined;\n let componentId = _componentId;\n\n if (components[`${_componentId}.ts`]) {\n componentId = `${_componentId}.ts`;\n componentLoader = components[componentId] as ComponentLoader;\n }\n\n return { componentLoader, componentId };\n}\n\nfunction retrieveTransferredState(\n html: string,\n appId: string,\n): Record<string, unknown | undefined> {\n const regex = new RegExp(\n `<script id=\"${appId}-state\" type=\"application/json\">(.*?)</script>`,\n );\n const match = html.match(regex);\n\n if (match) {\n const scriptContent = match[1];\n\n if (scriptContent) {\n try {\n const parsedContent: {\n _analog_output: Record<string, unknown | undefined>;\n } = JSON.parse(scriptContent);\n return parsedContent._analog_output || {};\n } catch (e) {\n console.warn('Exception while parsing static outputs for ' + appId, e);\n }\n }\n\n return {};\n } else {\n return {};\n }\n}\n","import {\n ApplicationConfig,\n Provider,\n Type,\n enableProdMode,\n} from '@angular/core';\nimport {\n bootstrapApplication,\n type BootstrapContext,\n} from '@angular/platform-browser';\nimport { renderApplication } from '@angular/platform-server';\nimport type { ServerContext } from '@analogjs/router/tokens';\n\nimport { provideServerContext } from './provide-server-context';\nimport {\n serverComponentRequest,\n renderServerComponent,\n} from './server-component-render';\n\nif (import.meta.env.PROD) {\n enableProdMode();\n}\n\n/**\n * Returns a function that accepts the navigation URL,\n * the root HTML, and server context.\n *\n * @param rootComponent\n * @param config\n * @param platformProviders\n * @returns Promise<string | Reponse>\n */\nexport function render(\n rootComponent: Type<unknown>,\n config: ApplicationConfig,\n platformProviders: Provider[] = [],\n) {\n function bootstrap(context?: BootstrapContext) {\n return bootstrapApplication(rootComponent, config, context);\n }\n\n return async function render(\n url: string,\n document: string,\n serverContext: ServerContext,\n ): Promise<string | Response> {\n if (serverComponentRequest(serverContext)) {\n return await renderServerComponent(url, serverContext);\n }\n\n const html = await renderApplication(bootstrap, {\n document,\n url,\n platformProviders: [\n provideServerContext(serverContext),\n platformProviders,\n ],\n });\n\n return html;\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analogjs-router-tanstack-query.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"analogjs-router-tanstack-query.mjs","names":[],"sources":["../../tanstack-query/src/provide-analog-query.ts","../../tanstack-query/src/server-query.ts"],"sourcesContent":["import {\n ENVIRONMENT_INITIALIZER,\n TransferState,\n inject,\n makeEnvironmentProviders,\n makeStateKey,\n} from '@angular/core';\nimport type { EnvironmentProviders, StateKey } from '@angular/core';\nimport { QueryClient, hydrate } from '@tanstack/angular-query-experimental';\nimport type { DehydratedState } from '@tanstack/angular-query-experimental';\n\nexport const ANALOG_QUERY_STATE_KEY: StateKey<DehydratedState> =\n makeStateKey<DehydratedState>('analog_query_state');\n\nexport function provideAnalogQuery(): EnvironmentProviders {\n return makeEnvironmentProviders([\n {\n provide: ENVIRONMENT_INITIALIZER,\n multi: true,\n useValue() {\n if (import.meta.env.SSR) {\n return;\n }\n\n const transferState = inject(TransferState);\n const client = inject(QueryClient);\n const dehydratedState = transferState.get<DehydratedState | null>(\n ANALOG_QUERY_STATE_KEY,\n null,\n );\n\n if (dehydratedState) {\n hydrate(client, dehydratedState);\n transferState.remove(ANALOG_QUERY_STATE_KEY);\n }\n },\n },\n ]);\n}\n","import type { HttpClient } from '@angular/common/http';\nimport { lastValueFrom } from 'rxjs';\nimport type {\n CreateQueryOptions,\n CreateMutationOptions,\n CreateInfiniteQueryOptions,\n DefaultError,\n InfiniteData,\n QueryKey,\n} from '@tanstack/angular-query-experimental';\nimport type {\n ServerRouteHandler,\n InferRouteQuery,\n InferRouteBody,\n InferRouteResult,\n} from '@analogjs/router/server/actions';\n\nfunction buildUrl(base: string, params?: Record<string, unknown>): string {\n if (!params) return base;\n const parts: string[] = [];\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) continue;\n const k = encodeURIComponent(key);\n if (Array.isArray(value)) {\n for (const item of value) {\n parts.push(`${k}=${encodeURIComponent(String(item))}`);\n }\n } else {\n parts.push(`${k}=${encodeURIComponent(String(value))}`);\n }\n }\n if (parts.length === 0) return base;\n const separator = base.includes('?') ? '&' : '?';\n return `${base}${separator}${parts.join('&')}`;\n}\n\nexport function serverQueryOptions<\n TRoute extends ServerRouteHandler<any, any, any>,\n TError = DefaultError,\n TData = InferRouteResult<TRoute>,\n TQueryKey extends QueryKey = QueryKey,\n>(\n http: HttpClient,\n url: string,\n options: { queryKey: TQueryKey; query?: InferRouteQuery<TRoute> } & Omit<\n CreateQueryOptions<InferRouteResult<TRoute>, TError, TData, TQueryKey>,\n 'queryKey' | 'queryFn'\n >,\n): CreateQueryOptions<InferRouteResult<TRoute>, TError, TData, TQueryKey> {\n const { query, ...rest } = options;\n return {\n ...rest,\n queryFn: () =>\n lastValueFrom(\n http.get<InferRouteResult<TRoute>>(\n buildUrl(url, query as Record<string, any>),\n ),\n ),\n } as CreateQueryOptions<InferRouteResult<TRoute>, TError, TData, TQueryKey>;\n}\n\nexport function serverMutationOptions<\n TRoute extends ServerRouteHandler<any, any, any>,\n TError = DefaultError,\n TOnMutateResult = unknown,\n>(\n http: HttpClient,\n url: string,\n options?: Omit<\n CreateMutationOptions<\n InferRouteResult<TRoute>,\n TError,\n InferRouteBody<TRoute>,\n TOnMutateResult\n >,\n 'mutationFn'\n >,\n): CreateMutationOptions<\n InferRouteResult<TRoute>,\n TError,\n InferRouteBody<TRoute>,\n TOnMutateResult\n> {\n return {\n mutationFn: (body: InferRouteBody<TRoute>) =>\n lastValueFrom(http.post<InferRouteResult<TRoute>>(url, body)),\n ...options,\n } as CreateMutationOptions<\n InferRouteResult<TRoute>,\n TError,\n InferRouteBody<TRoute>,\n TOnMutateResult\n >;\n}\n\nexport function serverInfiniteQueryOptions<\n TRoute extends ServerRouteHandler<any, any, any>,\n TError = DefaultError,\n TData = InfiniteData<InferRouteResult<TRoute>>,\n TQueryKey extends QueryKey = QueryKey,\n TPageParam = unknown,\n>(\n http: HttpClient,\n url: string,\n options: {\n queryKey: TQueryKey;\n query: (context: { pageParam: TPageParam }) => InferRouteQuery<TRoute>;\n initialPageParam: TPageParam;\n getNextPageParam: (\n lastPage: InferRouteResult<TRoute>,\n allPages: InferRouteResult<TRoute>[],\n ) => TPageParam | undefined | null;\n } & Omit<\n CreateInfiniteQueryOptions<\n InferRouteResult<TRoute>,\n TError,\n TData,\n TQueryKey,\n TPageParam\n >,\n 'queryKey' | 'queryFn' | 'initialPageParam' | 'getNextPageParam'\n >,\n): CreateInfiniteQueryOptions<\n InferRouteResult<TRoute>,\n TError,\n TData,\n TQueryKey,\n TPageParam\n> {\n const { query: buildQuery, ...rest } = options;\n return {\n ...rest,\n queryFn: (context: { pageParam: TPageParam }) =>\n lastValueFrom(\n http.get<InferRouteResult<TRoute>>(\n buildUrl(url, buildQuery(context) as Record<string, any>),\n ),\n ),\n } as CreateInfiniteQueryOptions<\n InferRouteResult<TRoute>,\n TError,\n TData,\n TQueryKey,\n TPageParam\n >;\n}\n"],"mappings":";;;;AAWA,IAAa,yBACX,aAA8B,qBAAqB;AAErD,SAAgB,qBAA2C;AACzD,QAAO,yBACL,CACE;EACO,SAAA;EACP,OAAW;EACL,WAAgB;GAKd,MAAS,gBAAmB,OAAA,cAAA;GAC5B,MAAA,SAAkB,OAAA,YACtB;GAIE,MAAA,kBAAiB,cAAA,IAAA,wBAAA,KAAA;AACX,OAAQ,iBAAgB;AAClB,YAAO,QAAA,gBAAuB;;;;;;;;AChBtD,SAAS,SAAS,MAAc,QAA0C;AACxE,KAAK,CAAA,OACC,QAAkB;CACxB,MAAK,QAAY,EAAA;AACf,MAAI,MAAA,CAAU,KAAA,UAAa,OAAA,QAAgB,OAAA,EAAA;AACrC,MAAI,UAAA,KAAA,KAAuB,UAAA,KACvB;EACH,MAAM,IAAA,mBAAe,IAAA;AACxB,MAAM,MAAQ,QAAK,MAAA,CAAA,MAAA,MAAA,QAAA,MAEhB,OAAA,KAAA,GAAA,EAAA,GAAA,mBAAA,OAAA,KAAA,CAAA,GAAA;MAIC,OAAA,KAAW,GAAG,EAAA,GAAA,mBAAO,OAAA,MAAA,CAAA,GAAA;;wBAK1B,QAAA;AAcL,QAAO,GAAA,OADW,KAAA,SAAS,IAAA,GAAA,MAAA,MACpB,MAAA,KAAA,IAAA;;SAEL,mBAEI,MACE,KAAA,SAAc;CAGrB,MAAA,EAAA,OAAA,GAAA,SAAA;;EAGI,GAAA;EAsBE,eAAA,cAAA,KAAA,IAAA,SAAA,KAAA,MAAA,CAAA,CAAA;EACL;;SAGD,sBAAA,MAAA,KAAA,SAAA;;EAQI,aAAS,SAAA,cAOd,KACA,KACA,KAAA,KAwBA,CAAA;EACM,GAAE;EACR;;SAEY,2BAED,MACH,KAAA,SAAc;CAGrB,MAAA,EAAA,OAAA,YAAA,GAAA,SAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analogjs-router-tokens.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"analogjs-router-tokens.mjs","names":[],"sources":["../../tokens/src/index.ts"],"sourcesContent":["import { InjectionToken, inject } from '@angular/core';\nimport type { $Fetch } from 'nitro/types';\nimport type {\n IncomingMessage,\n ServerResponse as NodeServerResponse,\n} from 'node:http';\n\nexport type ServerRequest = IncomingMessage & { originalUrl: string };\nexport type ServerResponse = NodeServerResponse;\nexport type ServerInternalFetch = $Fetch;\nexport type ServerContext = {\n req: ServerRequest;\n res: ServerResponse;\n fetch?: ServerInternalFetch;\n};\n\nexport const REQUEST: InjectionToken<ServerRequest> =\n new InjectionToken<ServerRequest>('@analogjs/router Server Request');\nexport const RESPONSE: InjectionToken<ServerResponse> =\n new InjectionToken<ServerResponse>('@analogjs/router Server Response');\nexport const BASE_URL: InjectionToken<string> = new InjectionToken<string>(\n '@analogjs/router Base URL',\n);\nexport const INTERNAL_FETCH: InjectionToken<ServerInternalFetch> =\n new InjectionToken<ServerInternalFetch>(\n '@analogjs/router Internal Server Fetch',\n );\n\nexport const API_PREFIX: InjectionToken<string> = new InjectionToken<string>(\n '@analogjs/router API Prefix',\n);\n\nexport function injectRequest(): ServerRequest | null {\n return inject(REQUEST, { optional: true });\n}\n\nexport function injectResponse(): ServerResponse | null {\n return inject(RESPONSE, { optional: true });\n}\n\nexport function injectBaseURL(): string | null {\n return inject(BASE_URL, { optional: true });\n}\n\nexport function injectInternalServerFetch(): ServerInternalFetch | null {\n return inject(INTERNAL_FETCH, { optional: true });\n}\n\nexport function injectAPIPrefix(): string {\n return inject(API_PREFIX);\n}\n"],"mappings":";;AAgBA,IAAa,UACX,IAAI,eAA8B,kCAAkC;AACtE,IAAa,WACX,IAAI,eAA+B,mCAAmC;AACxE,IAAa,WAAmC,IAAI,eAClD,4BACD;AACD,IAAa,iBACX,IAAI,eACF,yCACD;AAEH,IAAa,aAAqC,IAAI,eACpD,8BACD;AAED,SAAgB,gBAAsC;AACpD,QAAO,OAAO,SAAW,EAAA,UAAU,MAAO,CAAA;;AAG5C,SAAgB,iBAAwC;AACtD,QAAO,OAAO,UAAY,EAAA,UAAU,MAAO,CAAA;;AAG7C,SAAgB,gBAA+B;AAC7C,QAAO,OAAO,UAAY,EAAA,UAAU,MAAO,CAAA;;AAG7C,SAAgB,4BAAwD;AACtE,QAAO,OAAO,gBAAkB,EAAA,UAAU,MAAO,CAAA;;AAGnD,SAAgB,kBAA0B;AACxC,QAAO,OAAO,WAAW"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analogjs-router.mjs","names":[],"sources":["../../../../packages/router/src/lib/define-route.ts","../../../../packages/router/src/lib/cookie-interceptor.ts","../../../../packages/router/src/lib/provide-file-router.ts","../../../../packages/router/src/lib/inject-load.ts","../../../../packages/router/src/lib/get-load-resolver.ts","../../../../packages/router/src/lib/cache-key.ts","../../../../packages/router/src/lib/request-context.ts","../../../../packages/router/src/lib/form-action.directive.ts","../../../../packages/router/src/lib/debug/index.ts","../../../../packages/router/src/lib/server.component.ts","../../../../packages/router/src/lib/validation-errors.ts","../../../../packages/router/src/lib/route-path.ts","../../../../packages/router/src/lib/inject-navigate.ts","../../../../packages/router/src/lib/experimental.ts","../../../../packages/router/src/lib/inject-typed-params.ts","../../../../packages/router/src/lib/inject-route-context.ts"],"sourcesContent":["import { inject } from '@angular/core';\nimport { Route as NgRoute, Router } from '@angular/router';\nimport { ActivatedRoute } from '@angular/router';\n\nimport { AnalogJsonLdDocument } from './json-ld';\nimport { MetaTag } from './meta-tags';\n\ntype RouteOmitted =\n | 'component'\n | 'loadComponent'\n | 'loadChildren'\n | 'path'\n | 'pathMatch';\n\ntype RestrictedRoute = Omit<NgRoute, RouteOmitted> & {\n meta?: MetaTag[];\n jsonLd?: AnalogJsonLdDocument;\n};\n\n/**\n * @deprecated Use `RouteMeta` type instead.\n * For more info see: https://github.com/analogjs/analog/issues/223\n *\n * Defines additional route config metadata. This\n * object is merged into the route config with\n * the predefined file-based route.\n *\n * @usageNotes\n *\n * ```\n * import { Component } from '@angular/core';\n * import { defineRouteMeta } from '@analogjs/router';\n *\n * export const routeMeta = defineRouteMeta({\n * title: 'Welcome'\n * });\n *\n * @Component({\n * template: `Home`,\n * standalone: true,\n * })\n * export default class HomeComponent {}\n * ```\n *\n * @param route\n * @returns\n */\nexport const defineRouteMeta = (route: RestrictedRoute): RestrictedRoute => {\n return route;\n};\n\n/**\n * Returns the instance of Angular Router\n *\n * @returns The router\n */\nexport const injectRouter = (): Router => {\n return inject(Router);\n};\n\n/**\n * Returns the instance of the Activate Route for the component\n *\n * @returns The activated route\n */\nexport const injectActivatedRoute = (): ActivatedRoute => {\n return inject(ActivatedRoute);\n};\n","import { isPlatformServer } from '@angular/common';\nimport {\n HttpHandlerFn,\n HttpHeaders,\n HttpRequest,\n HttpEvent,\n} from '@angular/common/http';\nimport { PLATFORM_ID, inject } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { injectRequest, ServerRequest } from '@analogjs/router/tokens';\n\nexport function cookieInterceptor(\n req: HttpRequest<unknown>,\n next: HttpHandlerFn,\n location: object = inject(PLATFORM_ID),\n serverRequest: ServerRequest | null = injectRequest(),\n): Observable<HttpEvent<unknown>> {\n if (isPlatformServer(location) && req.url.includes('/_analog/')) {\n let headers = new HttpHeaders();\n const cookies = serverRequest?.headers.cookie;\n headers = headers.set('cookie', cookies ?? '');\n\n const cookiedRequest = req.clone({\n headers,\n });\n\n return next(cookiedRequest);\n } else {\n return next(req);\n }\n}\n","import {\n ENVIRONMENT_INITIALIZER,\n EnvironmentProviders,\n makeEnvironmentProviders,\n} from '@angular/core';\nimport { provideRouter, RouterFeatures, ROUTES, Routes } from '@angular/router';\nimport { API_PREFIX } from '@analogjs/router/tokens';\nimport { ɵHTTP_ROOT_INTERCEPTOR_FNS as HTTP_ROOT_INTERCEPTOR_FNS } from '@angular/common/http';\n\nimport { routes } from './routes';\nimport { updateJsonLdOnRouteChange } from './json-ld';\nimport { updateMetaTagsOnRouteChange } from './meta-tags';\nimport { cookieInterceptor } from './cookie-interceptor';\n\ndeclare const ANALOG_API_PREFIX: string;\n\n/**\n * Sets up providers for the Angular router, and registers\n * file-based routes. Additional features can be provided\n * to further configure the behavior of the router.\n *\n * @param features\n * @returns Providers and features to configure the router with routes\n */\nexport function provideFileRouter(\n ...features: RouterFeatures[]\n): EnvironmentProviders {\n const extraRoutesFeature = features.filter((feat) => feat.ɵkind >= 100);\n const routerFeatures = features.filter((feat) => feat.ɵkind < 100);\n\n return makeEnvironmentProviders([\n extraRoutesFeature.map((erf) => erf.ɵproviders),\n provideRouter(routes, ...routerFeatures),\n {\n provide: ENVIRONMENT_INITIALIZER,\n multi: true,\n useValue: () => updateMetaTagsOnRouteChange(),\n },\n {\n provide: ENVIRONMENT_INITIALIZER,\n multi: true,\n useValue: () => updateJsonLdOnRouteChange(),\n },\n {\n provide: HTTP_ROOT_INTERCEPTOR_FNS,\n multi: true,\n useValue: cookieInterceptor,\n },\n {\n provide: API_PREFIX,\n useFactory() {\n return typeof ANALOG_API_PREFIX !== 'undefined'\n ? ANALOG_API_PREFIX\n : 'api';\n },\n },\n ]);\n}\n\n/**\n * Provides extra custom routes in addition to the routes\n * discovered from the filesystem-based routing. These routes are\n * inserted before the filesystem-based routes, and take priority in\n * route matching.\n */\nexport function withExtraRoutes(routes: Routes): RouterFeatures {\n return {\n ɵkind: 100 as number,\n ɵproviders: [{ provide: ROUTES, useValue: routes, multi: true }],\n };\n}\n","import { Injector, inject } from '@angular/core';\nimport { ActivatedRoute, Data } from '@angular/router';\nimport { Observable, map } from 'rxjs';\n\nimport { LoadDataResult, PageServerLoad } from './route-types';\n\nfunction isResponse(value: unknown): value is Response {\n return typeof value === 'object' && value instanceof Response;\n}\n\nexport function injectLoad<\n T extends (pageServerLoad: PageServerLoad) => Promise<any>,\n>(options?: { injector?: Injector }): Observable<Awaited<ReturnType<T>>> {\n const injector = options?.injector ?? inject(Injector);\n const route = injector.get(ActivatedRoute);\n\n return route.data.pipe(\n map<Data, Awaited<ReturnType<T>>>((data) => data['load']),\n );\n}\n\nexport function injectLoadData<\n T extends (pageServerLoad: PageServerLoad) => Promise<any>,\n>(options?: { injector?: Injector }): Observable<LoadDataResult<T>> {\n return injectLoad<T>(options).pipe(\n map((result): LoadDataResult<T> => {\n if (isResponse(result)) {\n throw new Error('Expected page load data but received a response.');\n }\n\n return result as LoadDataResult<T>;\n }),\n );\n}\n","import { ActivatedRouteSnapshot } from '@angular/router';\n\n/**\n * Get server load resolver data for the route\n *\n * @param route Provides the route to get server load resolver\n * @returns Returns server load resolver data for the route\n */\nexport async function getLoadResolver<T>(\n route: ActivatedRouteSnapshot,\n): Promise<T> {\n return route.routeConfig?.resolve?.['load']?.(route);\n}\n","import { HttpParams, HttpRequest } from '@angular/common/http';\nimport { StateKey, makeStateKey } from '@angular/core';\n\nfunction sortAndConcatParams(params: HttpParams | URLSearchParams): string {\n return [...params.keys()]\n .sort()\n .map((k) => `${k}=${params.getAll(k)}`)\n .join('&');\n}\n\nexport function makeCacheKey(\n request: HttpRequest<any>,\n mappedRequestUrl: string,\n): StateKey<unknown> {\n // make the params encoded same as a url so it's easy to identify\n const { params, method, responseType } = request;\n const encodedParams = sortAndConcatParams(params);\n\n let serializedBody = request.serializeBody();\n if (serializedBody instanceof URLSearchParams) {\n serializedBody = sortAndConcatParams(serializedBody);\n } else if (typeof serializedBody !== 'string') {\n serializedBody = '';\n }\n\n const key = [\n method,\n responseType,\n mappedRequestUrl,\n serializedBody,\n encodedParams,\n ].join('|');\n\n const hash = generateHash(key);\n\n return makeStateKey(hash);\n}\n\nfunction generateHash(str: string) {\n let hash = 0;\n for (let i = 0, len = str.length; i < len; i++) {\n const chr = str.charCodeAt(i);\n hash = (hash << 5) - hash + chr;\n hash |= 0; // Convert to 32bit integer\n }\n return `${hash}`;\n}\n","import { TransferState, inject, makeStateKey } from '@angular/core';\nimport {\n HttpEvent,\n HttpHandlerFn,\n HttpHeaders,\n HttpRequest,\n HttpResponse,\n} from '@angular/common/http';\n\nimport { from, Observable, of } from 'rxjs';\n\nimport {\n injectBaseURL,\n injectAPIPrefix,\n injectInternalServerFetch,\n} from '@analogjs/router/tokens';\n\nimport { makeCacheKey } from './cache-key';\n\n/**\n * Interceptor that is server-aware when making HttpClient requests.\n * Server-side requests use the full URL\n * Prerendering uses the internal Nitro $fetch function, along with state transfer\n * Client-side requests use the window.location.origin\n *\n * @param req HttpRequest<unknown>\n * @param next HttpHandlerFn\n * @returns\n */\nexport function requestContextInterceptor(\n req: HttpRequest<unknown>,\n next: HttpHandlerFn,\n): Observable<HttpEvent<unknown>> {\n const apiPrefix = injectAPIPrefix();\n const baseUrl = injectBaseURL();\n const transferState = inject(TransferState);\n const nitroGlobal = globalThis as typeof globalThis & { $fetch?: any };\n const internalFetch = injectInternalServerFetch();\n const serverFetch = internalFetch ?? nitroGlobal.$fetch;\n\n // during prerendering with Nitro\n if (\n serverFetch &&\n baseUrl &&\n (req.url.startsWith('/') ||\n req.url.startsWith(baseUrl) ||\n req.url.startsWith(`/${apiPrefix}`))\n ) {\n const requestUrl = new URL(req.url, baseUrl);\n const cacheKey = makeCacheKey(req, new URL(requestUrl).pathname);\n const storeKey = makeStateKey<unknown>(`analog_${cacheKey}`);\n const fetchUrl = requestUrl.pathname;\n\n const responseType =\n req.responseType === 'arraybuffer' ? 'arrayBuffer' : req.responseType;\n\n return from<Promise<HttpResponse<unknown>>>(\n serverFetch\n .raw(fetchUrl, {\n method: req.method as any,\n body: req.body ? req.body : undefined,\n params: requestUrl.searchParams,\n responseType,\n headers: req.headers\n .keys()\n .reduce((hdrs: Record<string, string | null>, current: string) => {\n return {\n ...hdrs,\n [current]: req.headers.get(current),\n };\n }, {}),\n })\n .then((res: any) => {\n const cacheResponse = {\n body: res._data,\n headers: new HttpHeaders(res.headers),\n status: res.status ?? 200,\n statusText: res.statusText ?? 'OK',\n url: fetchUrl,\n };\n const transferResponse = new HttpResponse(cacheResponse);\n\n transferState.set(storeKey, cacheResponse);\n return transferResponse;\n }),\n );\n }\n\n // on the client\n if (\n !import.meta.env.SSR &&\n (req.url.startsWith('/') || req.url.includes('/_analog/'))\n ) {\n // /_analog/ requests are full URLs\n const requestUrl = req.url.includes('/_analog/')\n ? req.url\n : `${window.location.origin}${req.url}`;\n const cacheKey = makeCacheKey(req, new URL(requestUrl).pathname);\n const storeKey = makeStateKey<unknown>(`analog_${cacheKey}`);\n const cacheRestoreResponse = transferState.get(storeKey, null);\n\n if (cacheRestoreResponse) {\n transferState.remove(storeKey);\n return of(new HttpResponse(cacheRestoreResponse));\n }\n\n return next(\n req.clone({\n url: requestUrl,\n }),\n );\n }\n\n // on the server\n if (baseUrl && (req.url.startsWith('/') || req.url.startsWith(baseUrl))) {\n const requestUrl =\n req.url.startsWith(baseUrl) && !req.url.startsWith('/')\n ? req.url\n : `${baseUrl}${req.url}`;\n\n return next(\n req.clone({\n url: requestUrl,\n }),\n );\n }\n\n return next(req);\n}\n","import {\n Directive,\n inject,\n input,\n output,\n signal,\n type InputSignal,\n type OutputEmitterRef,\n type WritableSignal,\n} from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\n\nimport { injectRouteEndpointURL } from './inject-route-endpoint-url';\n\nexport type FormActionState =\n | 'submitting'\n | 'error'\n | 'redirect'\n | 'success'\n | 'navigate';\n\n@Directive({\n // eslint-disable-next-line @angular-eslint/directive-selector\n selector: 'form[action],form[method]',\n host: {\n '(submit)': `submitted($event)`,\n '[attr.data-state]': 'currentState()',\n '[attr.aria-busy]': 'currentState() === \"submitting\" ? \"true\" : null',\n },\n standalone: true,\n})\nexport class FormAction {\n action: InputSignal<string> = input<string>('');\n // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n onSuccess: OutputEmitterRef<unknown> = output<unknown>();\n // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n onError: OutputEmitterRef<unknown> = output<unknown>();\n state: OutputEmitterRef<FormActionState> = output<FormActionState>();\n private router = inject(Router);\n private route = inject(ActivatedRoute);\n protected currentState: WritableSignal<FormActionState | 'idle'> = signal<\n FormActionState | 'idle'\n >('idle');\n /** Cached during construction (injection context) so inject() works. */\n private _endpointUrl = this.route\n ? injectRouteEndpointURL(this.route.snapshot)\n : undefined;\n\n submitted($event: any): void {\n $event.preventDefault();\n\n const form = $event.target as HTMLFormElement;\n this._emitState('submitting');\n const body = new FormData(form);\n\n if (form.method.toUpperCase() === 'GET') {\n this._handleGet(body, this._getGetPath(form));\n } else {\n this._handlePost(body, this._getPostPath(form), form.method);\n }\n }\n\n private _handleGet(body: FormData, path: string) {\n const url = new URL(path, window.location.href);\n const params = new URLSearchParams(url.search);\n body.forEach((value, key) => {\n params.append(key, value instanceof File ? value.name : value);\n });\n url.search = params.toString();\n\n this._emitState('navigate');\n this._navigateTo(url);\n }\n\n private _handlePost(body: FormData, path: string, method: string) {\n fetch(path, {\n method,\n body,\n })\n .then((res) => {\n if (res.ok) {\n if (res.redirected) {\n this._emitState('redirect');\n this._navigateTo(new URL(res.url, window.location.href));\n } else if (this._isJSON(res.headers.get('Content-type'))) {\n res.json().then((result) => {\n this.onSuccess.emit(result);\n this._emitState('success');\n });\n } else {\n res.text().then((result) => {\n this.onSuccess.emit(result);\n this._emitState('success');\n });\n }\n } else {\n if (res.headers.get('X-Analog-Errors')) {\n res.json().then((errors: unknown) => {\n this.onError.emit(errors);\n this._emitState('error');\n });\n } else {\n this._emitState('error');\n }\n }\n })\n .catch((_) => {\n this._emitState('error');\n });\n }\n\n private _getExplicitAction(form: HTMLFormElement) {\n const explicitAction =\n this.action().trim() || form.getAttribute('action')?.trim();\n return explicitAction || undefined;\n }\n\n private _getGetPath(form: HTMLFormElement) {\n return this._getExplicitAction(form) ?? this.router.url;\n }\n\n private _getPostPath(form: HTMLFormElement) {\n const explicitAction = this._getExplicitAction(form);\n if (explicitAction) {\n return new URL(explicitAction, window.location.href).toString();\n }\n\n if (this._endpointUrl) {\n return this._endpointUrl.pathname;\n }\n\n return `/api/_analog/pages${window.location.pathname}`;\n }\n\n private _emitState(state: FormActionState) {\n this.currentState.set(state);\n this.state.emit(state);\n }\n\n private _navigateTo(url: URL) {\n if (url.origin === window.location.origin) {\n void this.router.navigateByUrl(\n `${url.pathname}${url.search}${url.hash}`,\n {\n onSameUrlNavigation: 'reload',\n },\n );\n return;\n }\n\n window.location.assign(url.toString());\n }\n\n private _isJSON(contentType: string | null): boolean {\n const mime = contentType ? contentType.split(';') : [];\n const essence = mime[0];\n\n return essence === 'application/json';\n }\n}\n","import { EnvironmentProviders, Provider } from '@angular/core';\nimport { ROUTES } from '@angular/router';\n\n/**\n * Provides routes that provide additional\n * pages for displaying and debugging\n * routes.\n */\nexport function withDebugRoutes(): {\n ɵkind: number;\n ɵproviders: (Provider | EnvironmentProviders)[];\n} {\n const routes = [\n {\n path: '__analog/routes',\n loadComponent: () => import('./debug.page'),\n },\n ];\n\n return {\n ɵkind: 101 as number,\n ɵproviders: [{ provide: ROUTES, useValue: routes, multi: true }],\n };\n}\n","import {\n HttpClient,\n HttpHeaders,\n HttpRequest,\n HttpResponse,\n} from '@angular/common/http';\nimport {\n ChangeDetectionStrategy,\n Component,\n effect,\n inject,\n input,\n InputSignal,\n makeStateKey,\n output,\n OutputEmitterRef,\n signal,\n TransferState,\n WritableSignal,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { ActivatedRoute } from '@angular/router';\nimport { injectBaseURL } from '@analogjs/router/tokens';\nimport { catchError, map, of, throwError } from 'rxjs';\n\nimport { makeCacheKey } from './cache-key';\n\ntype ServerProps = Record<string, any>;\ntype ServerOutputs = Record<string, any>;\n\n/**\n * @description\n * Component that defines the bridge between the client and server-only\n * components. The component passes the component ID and props to the server\n * and retrieves the rendered HTML and outputs from the server-only component.\n *\n * Status: experimental\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'server-only,ServerOnly,Server',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: ` <div [innerHTML]=\"content()\"></div> `,\n})\nexport class ServerOnly {\n component: InputSignal<string> = input.required<string>();\n props: InputSignal<ServerProps | undefined> = input<ServerProps>();\n outputs: OutputEmitterRef<ServerOutputs> = output<ServerOutputs>();\n private http: HttpClient = inject(HttpClient);\n private sanitizer: DomSanitizer = inject(DomSanitizer);\n protected content: WritableSignal<SafeHtml> = signal<SafeHtml>('');\n private route: ActivatedRoute | null = inject(ActivatedRoute, {\n optional: true,\n });\n private baseURL: string | null = injectBaseURL();\n private transferState = inject(TransferState);\n\n constructor() {\n effect(() => {\n const routeComponentId: string | undefined =\n this.route?.snapshot.data['component'];\n const props = this.props() || {};\n const componentId = routeComponentId || this.component();\n\n const headers = new HttpHeaders(\n new Headers({\n 'Content-type': 'application/json',\n 'X-Analog-Component': componentId,\n }),\n );\n\n const componentUrl = this.getComponentUrl(componentId);\n const httpRequest = new HttpRequest('POST', componentUrl, props, {\n headers,\n });\n const cacheKey = makeCacheKey(\n httpRequest,\n new URL(componentUrl).pathname,\n );\n const storeKey = makeStateKey<{ html: string; outputs: ServerOutputs }>(\n cacheKey,\n );\n const componentState = this.transferState.get<{\n html: string;\n outputs: ServerOutputs;\n } | null>(storeKey, null);\n\n if (componentState) {\n this.updateContent(componentState);\n this.transferState.remove(storeKey);\n } else {\n this.http\n .request(httpRequest)\n .pipe(\n map((response) => {\n if (response instanceof HttpResponse) {\n if (import.meta.env.SSR) {\n this.transferState.set(storeKey, response.body);\n }\n\n return response.body as {\n html: string;\n outputs: ServerOutputs;\n };\n }\n return throwError(\n () => ({}) as { html: string; outputs: ServerOutputs },\n );\n }),\n catchError((error: unknown) => {\n console.log(error);\n return of({\n html: '',\n outputs: {} as ServerOutputs,\n });\n }),\n )\n .subscribe((content) =>\n this.updateContent(\n content as { html: string; outputs: ServerOutputs },\n ),\n );\n }\n });\n }\n\n updateContent(content: { html: string; outputs: ServerOutputs }): void {\n this.content.set(this.sanitizer.bypassSecurityTrustHtml(content.html));\n this.outputs.emit(content.outputs);\n }\n\n getComponentUrl(componentId: string) {\n let baseURL = this.baseURL;\n\n if (!baseURL && typeof window !== 'undefined') {\n baseURL = window.location.origin;\n }\n\n return `${baseURL}/_analog/components/${componentId}`;\n }\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\n\nexport type ValidationFieldErrors = Record<string, string[]>;\n\nfunction getPathSegmentKey(\n segment: string | number | symbol | { key: string | number | symbol },\n) {\n return typeof segment === 'object' ? segment.key : segment;\n}\n\nexport function issuePathToFieldName(\n path: ReadonlyArray<\n string | number | symbol | { key: string | number | symbol }\n >,\n): string {\n return path.map((segment) => String(getPathSegmentKey(segment))).join('.');\n}\n\nexport function issuesToFieldErrors(\n issues: ReadonlyArray<StandardSchemaV1.Issue>,\n): ValidationFieldErrors {\n return issues.reduce<ValidationFieldErrors>((errors, issue) => {\n if (!issue.path?.length) {\n return errors;\n }\n\n const fieldName = issuePathToFieldName(issue.path);\n errors[fieldName] ??= [];\n errors[fieldName].push(issue.message);\n return errors;\n }, {});\n}\n\nexport function issuesToFormErrors(\n issues: ReadonlyArray<StandardSchemaV1.Issue>,\n): string[] {\n return issues\n .filter((issue) => !issue.path?.length)\n .map((issue) => issue.message);\n}\n","/**\n * Typed route path utilities for Analog.\n *\n * This module provides:\n * - The `AnalogRouteTable` base interface (augmented by generated code)\n * - The `AnalogRoutePath` union type\n * - The `routePath()` URL builder function\n *\n * No Angular dependencies — can be used in any context.\n */\n\n/**\n * Base interface for the typed route table.\n *\n * This interface is augmented by generated code in `src/routeTree.gen.ts`.\n * When no routes are generated, it is empty and `AnalogRoutePath` falls\n * back to `string`.\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type\nexport interface AnalogRouteTable {}\n\n/**\n * Union of all valid route paths.\n *\n * When routes are generated, this is a string literal union.\n * When no routes are generated, this falls back to `string`.\n */\nexport type AnalogRoutePath = keyof AnalogRouteTable extends never\n ? string\n : Extract<keyof AnalogRouteTable, string>;\n\n/**\n * Options for building a route URL.\n */\nexport interface RoutePathOptionsBase {\n params?: Record<string, string | string[] | undefined>;\n query?: Record<string, string | string[] | undefined>;\n hash?: string;\n}\n\n/**\n * Extracts the validated output type for route params.\n *\n * When a route exports `routeParamsSchema`, this resolves to the schema's\n * output type (e.g., `{ id: number }` after coercion).\n * When no schema exists, this is the same as the navigation param type.\n */\nexport type RouteParamsOutput<P extends string> =\n P extends keyof AnalogRouteTable\n ? AnalogRouteTable[P] extends { paramsOutput: infer O }\n ? O\n : AnalogRouteTable[P] extends { params: infer Params }\n ? Params\n : Record<string, unknown>\n : Record<string, unknown>;\n\n/**\n * Extracts the validated output type for route query params.\n */\nexport type RouteQueryOutput<P extends string> =\n P extends keyof AnalogRouteTable\n ? AnalogRouteTable[P] extends { queryOutput: infer O }\n ? O\n : Record<string, string | string[] | undefined>\n : Record<string, string | string[] | undefined>;\n\ntype RequiredRouteParamKeys<Params> =\n Params extends Record<string, never>\n ? never\n : {\n [K in keyof Params]-?: Record<string, never> extends Pick<Params, K>\n ? never\n : K;\n }[keyof Params];\n\ntype HasRequiredRouteParams<Params> = [RequiredRouteParamKeys<Params>] extends [\n never,\n]\n ? false\n : true;\n\n/**\n * Typed options that infer params from the route table when available.\n */\nexport type RoutePathOptions<P extends string = string> =\n P extends keyof AnalogRouteTable\n ? AnalogRouteTable[P] extends { params: infer Params }\n ? Params extends Record<string, never>\n ? {\n query?: RouteQueryOutput<P>;\n hash?: string;\n }\n : HasRequiredRouteParams<Params> extends true\n ? {\n params: Params;\n query?: RouteQueryOutput<P>;\n hash?: string;\n }\n : {\n params?: Params;\n query?: RouteQueryOutput<P>;\n hash?: string;\n }\n : RoutePathOptionsBase\n : RoutePathOptionsBase;\n\n/**\n * Conditional args: require options when the route has params.\n */\nexport type RoutePathArgs<P extends string = string> =\n P extends keyof AnalogRouteTable\n ? AnalogRouteTable[P] extends { params: infer Params }\n ? Params extends Record<string, never>\n ? [options?: RoutePathOptions<P>]\n : HasRequiredRouteParams<Params> extends true\n ? [options: RoutePathOptions<P>]\n : [options?: RoutePathOptions<P>]\n : [options?: RoutePathOptionsBase]\n : [options?: RoutePathOptionsBase];\n\n/**\n * Result of `routePath()` — contains properties that map directly\n * to Angular's `[routerLink]`, `[queryParams]`, and `[fragment]` inputs.\n */\nexport interface RouteLinkResult {\n path: string;\n queryParams: Record<string, string | string[]> | null;\n fragment: string | undefined;\n}\n\n/**\n * Builds a typed route link object from a route path pattern and options.\n *\n * The returned object separates path, query params, and fragment for\n * direct use with Angular's routerLink directive inputs.\n *\n * @example\n * routePath('/about')\n * // → { path: '/about', queryParams: null, fragment: undefined }\n *\n * routePath('/users/[id]', { params: { id: '42' } })\n * // → { path: '/users/42', queryParams: null, fragment: undefined }\n *\n * routePath('/users/[id]', { params: { id: '42' }, query: { tab: 'settings' }, hash: 'bio' })\n * // → { path: '/users/42', queryParams: { tab: 'settings' }, fragment: 'bio' }\n *\n * @example Template usage\n * ```html\n * @let link = routePath('/users/[id]', { params: { id: userId } });\n * <a [routerLink]=\"link.path\" [queryParams]=\"link.queryParams\" [fragment]=\"link.fragment\">\n * ```\n */\nexport function routePath<P extends AnalogRoutePath>(\n path: P,\n ...args: RoutePathArgs<P>\n): RouteLinkResult {\n const options = args[0] as RoutePathOptionsBase | undefined;\n return buildRouteLink(path as string, options);\n}\n\n/**\n * Internal: builds a `RouteLinkResult` from path and options.\n * Exported for direct use in tests (avoids generic constraints).\n */\nexport function buildRouteLink(\n path: string,\n options?: RoutePathOptionsBase,\n): RouteLinkResult {\n const resolvedPath = buildPath(path, options?.params);\n\n let queryParams: Record<string, string | string[]> | null = null;\n if (options?.query) {\n const filtered: Record<string, string | string[]> = {};\n let hasEntries = false;\n for (const [key, value] of Object.entries(options.query)) {\n if (value !== undefined) {\n filtered[key] = value;\n hasEntries = true;\n }\n }\n if (hasEntries) {\n queryParams = filtered;\n }\n }\n\n return {\n path: resolvedPath,\n queryParams,\n fragment: options?.hash,\n };\n}\n\n/**\n * Resolves param placeholders and normalises slashes.\n * Returns only the path — no query string or hash.\n */\nfunction buildPath(\n path: string,\n params?: Record<string, string | string[] | undefined>,\n): string {\n let url = path;\n\n if (params) {\n // Replace [[...param]] — optional catch-all\n url = url.replace(/\\[\\[\\.\\.\\.([^\\]]+)\\]\\]/g, (_, name) => {\n const value = params[name];\n if (value == null) return '';\n if (Array.isArray(value)) {\n return value.map((v) => encodeURIComponent(v)).join('/');\n }\n return encodeURIComponent(String(value));\n });\n\n // Replace [...param] — required catch-all\n url = url.replace(/\\[\\.\\.\\.([^\\]]+)\\]/g, (_, name) => {\n const value = params[name];\n if (value == null) {\n throw new Error(\n `Missing required catch-all param \"${name}\" for path \"${path}\"`,\n );\n }\n if (Array.isArray(value)) {\n if (value.length === 0) {\n throw new Error(\n `Missing required catch-all param \"${name}\" for path \"${path}\"`,\n );\n }\n return value.map((v) => encodeURIComponent(v)).join('/');\n }\n return encodeURIComponent(String(value));\n });\n\n // Replace [param] — dynamic param\n url = url.replace(/\\[([^\\]]+)\\]/g, (_, name) => {\n const value = params[name];\n if (value == null) {\n throw new Error(`Missing required param \"${name}\" for path \"${path}\"`);\n }\n return encodeURIComponent(String(value));\n });\n } else {\n // Strip bracket syntax when no params provided\n url = url.replace(/\\[\\[\\.\\.\\.([^\\]]+)\\]\\]/g, '');\n url = url.replace(/\\[\\.\\.\\.([^\\]]+)\\]/g, '');\n url = url.replace(/\\[([^\\]]+)\\]/g, '');\n }\n\n // Clean up double/trailing slashes\n url = url.replace(/\\/+/g, '/');\n if (url.length > 1 && url.endsWith('/')) {\n url = url.slice(0, -1);\n }\n if (!url.startsWith('/')) {\n url = '/' + url;\n }\n\n return url;\n}\n\n/**\n * Internal URL builder. Separated from `routePath` so it can be\n * used without generic constraints (e.g., in `injectNavigate`).\n */\nexport function buildUrl(path: string, options?: RoutePathOptionsBase): string {\n let url = buildPath(path, options?.params);\n\n if (options?.query) {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(options.query)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const v of value) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(v)}`);\n }\n } else {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\n }\n }\n if (parts.length > 0) {\n url += '?' + parts.join('&');\n }\n }\n\n if (options?.hash) {\n url += '#' + options.hash;\n }\n\n return url;\n}\n","import { inject } from '@angular/core';\nimport { type NavigationBehaviorOptions, Router } from '@angular/router';\n\nimport type {\n AnalogRoutePath,\n RoutePathArgs,\n RoutePathOptionsBase,\n} from './route-path';\nimport { buildUrl } from './route-path';\n\ntype NavigateWithExtrasArgs<P extends AnalogRoutePath> =\n RoutePathArgs<P> extends [options?: infer Options]\n ?\n | [extras: NavigationBehaviorOptions]\n | [options: Options | undefined, extras: NavigationBehaviorOptions]\n : [options: RoutePathArgs<P>[0], extras: NavigationBehaviorOptions];\n\ntype TypedNavigate = {\n <P extends AnalogRoutePath>(\n path: P,\n ...args: RoutePathArgs<P>\n ): Promise<boolean>;\n <P extends AnalogRoutePath>(\n path: P,\n ...args: NavigateWithExtrasArgs<P>\n ): Promise<boolean>;\n};\n\nfunction isRoutePathOptionsBase(value: unknown): value is RoutePathOptionsBase {\n return (\n !!value &&\n typeof value === 'object' &&\n ('params' in value || 'query' in value || 'hash' in value)\n );\n}\n\n/**\n * Injects a typed navigate function.\n *\n * @example\n * ```ts\n * const navigate = injectNavigate();\n *\n * navigate('/users/[id]', { params: { id: '42' } }); // ✅\n * navigate('/users/[id]', { params: { id: 42 } }); // ❌ type error\n *\n * // With navigation extras\n * navigate('/users/[id]', { params: { id: '42' } }, { replaceUrl: true });\n * ```\n */\nexport function injectNavigate(): TypedNavigate {\n const router = inject(Router);\n\n const navigate = ((\n path: AnalogRoutePath,\n ...args: unknown[]\n ): Promise<boolean> => {\n let options: RoutePathOptionsBase | undefined;\n let extras: NavigationBehaviorOptions | undefined;\n\n if (args.length > 1) {\n options = args[0] as RoutePathOptionsBase | undefined;\n extras = args[1] as NavigationBehaviorOptions | undefined;\n } else if (args.length === 1) {\n if (isRoutePathOptionsBase(args[0])) {\n options = args[0];\n } else {\n extras = args[0] as NavigationBehaviorOptions;\n }\n }\n\n const url = buildUrl(path as string, options);\n return router.navigateByUrl(url, extras);\n }) as TypedNavigate;\n\n return navigate;\n}\n","import { InjectionToken } from '@angular/core';\nimport type { RouterFeatures } from '@angular/router';\n\n/**\n * Configuration for experimental typed router features.\n *\n * Inspired by TanStack Router's type-safe navigation system where\n * routes are registered globally and all navigation/hooks are typed\n * against the route tree.\n *\n * @experimental\n */\nexport interface TypedRouterOptions {\n /**\n * When true, logs warnings in development when navigating to\n * routes with params that don't match the generated route table.\n *\n * Similar to TanStack Router's strict mode where `useParams()`\n * without a `from` constraint returns a union of all possible params.\n *\n * @default false\n */\n strictRouteParams?: boolean;\n}\n\n/**\n * Configuration for experimental loader caching.\n *\n * Inspired by TanStack Router's built-in data caching where route\n * loaders automatically cache results and support stale-while-revalidate.\n *\n * @experimental\n */\nexport interface LoaderCacheOptions {\n /**\n * Time in milliseconds before loader data is considered stale.\n * While data is fresh, navigating back to the route uses cached\n * data without re-invoking the server load function.\n *\n * Mirrors TanStack Router's `defaultStaleTime` option on `createRouter()`.\n *\n * @default 0 (always re-fetch)\n */\n defaultStaleTime?: number;\n\n /**\n * Time in milliseconds to retain unused loader data in cache\n * after leaving a route. After this period the cached entry is\n * garbage-collected.\n *\n * Mirrors TanStack Router's `defaultGcTime` (default 30 min).\n *\n * @default 300_000 (5 minutes)\n */\n defaultGcTime?: number;\n\n /**\n * Delay in milliseconds before showing a pending/loading indicator\n * during route transitions. Prevents flash-of-loading-state for\n * fast navigations.\n *\n * Mirrors TanStack Router's `defaultPendingMs`.\n *\n * @default 0 (show immediately)\n */\n defaultPendingMs?: number;\n}\n\n// ---------------------------------------------------------------------------\n// DI tokens\n// ---------------------------------------------------------------------------\n\n/** @experimental */\nexport const EXPERIMENTAL_TYPED_ROUTER: InjectionToken<TypedRouterOptions> =\n new InjectionToken<TypedRouterOptions>('EXPERIMENTAL_TYPED_ROUTER');\n\n/** @experimental */\nexport const EXPERIMENTAL_ROUTE_CONTEXT: InjectionToken<\n Record<string, unknown>\n> = new InjectionToken<Record<string, unknown>>('EXPERIMENTAL_ROUTE_CONTEXT');\n\n/** @experimental */\nexport const EXPERIMENTAL_LOADER_CACHE: InjectionToken<LoaderCacheOptions> =\n new InjectionToken<LoaderCacheOptions>('EXPERIMENTAL_LOADER_CACHE');\n\n// ---------------------------------------------------------------------------\n// Provider feature functions (passed to provideFileRouter)\n// ---------------------------------------------------------------------------\n\n/**\n * Enables experimental typed router features.\n *\n * When active, `routePath()`, `injectNavigate()`, `injectParams()`,\n * and `injectQuery()` will enforce route table constraints and\n * optionally log warnings in strict mode.\n *\n * Inspired by TanStack Router's `Register` interface and strict type\n * checking across the entire navigation surface.\n *\n * @example\n * ```ts\n * provideFileRouter(\n * withTypedRouter({ strictRouteParams: true }),\n * )\n * ```\n *\n * @experimental\n */\nexport function withTypedRouter(options?: TypedRouterOptions): RouterFeatures {\n return {\n ɵkind: 102 as number,\n ɵproviders: [\n {\n provide: EXPERIMENTAL_TYPED_ROUTER,\n useValue: { strictRouteParams: false, ...options },\n },\n ],\n };\n}\n\n/**\n * Provides root-level route context available to all route loaders\n * and components via `injectRouteContext()`.\n *\n * Inspired by TanStack Router's `createRootRouteWithContext<T>()` where\n * a typed context object is required at router creation and automatically\n * available in every route's `beforeLoad` and `loader`.\n *\n * In Angular terms, this creates a DI token that server-side load\n * functions and components can inject to access shared services\n * without importing them individually.\n *\n * @example\n * ```ts\n * // app.config.ts\n * provideFileRouter(\n * withRouteContext({\n * auth: inject(AuthService),\n * db: inject(DatabaseService),\n * }),\n * )\n *\n * // In a component\n * const ctx = injectRouteContext<{ auth: AuthService; db: DatabaseService }>();\n * ```\n *\n * @experimental\n */\nexport function withRouteContext<T extends Record<string, unknown>>(\n context: T,\n): RouterFeatures {\n return {\n ɵkind: 103 as number,\n ɵproviders: [\n {\n provide: EXPERIMENTAL_ROUTE_CONTEXT,\n useValue: context,\n },\n ],\n };\n}\n\n/**\n * Configures experimental loader caching behavior for server-loaded\n * route data.\n *\n * Inspired by TanStack Router's built-in cache where `createRouter()`\n * accepts `defaultStaleTime` and `defaultGcTime` to control when\n * loaders re-execute and when cached data is discarded.\n *\n * @example\n * ```ts\n * provideFileRouter(\n * withLoaderCaching({\n * defaultStaleTime: 30_000, // 30s before re-fetch\n * defaultGcTime: 300_000, // 5min cache retention\n * defaultPendingMs: 200, // 200ms loading delay\n * }),\n * )\n * ```\n *\n * @experimental\n */\nexport function withLoaderCaching(\n options?: LoaderCacheOptions,\n): RouterFeatures {\n return {\n ɵkind: 104 as number,\n ɵproviders: [\n {\n provide: EXPERIMENTAL_LOADER_CACHE,\n useValue: {\n defaultStaleTime: 0,\n defaultGcTime: 300_000,\n defaultPendingMs: 0,\n ...options,\n },\n },\n ],\n };\n}\n","import { inject, Injector, isDevMode, Signal } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { map, take } from 'rxjs';\n\nimport type {\n AnalogRoutePath,\n RouteParamsOutput,\n RouteQueryOutput,\n} from './route-path';\nimport { EXPERIMENTAL_TYPED_ROUTER } from './experimental';\n\nfunction extractRouteParams(\n routePath: string,\n): { name: string; type: 'dynamic' | 'catchAll' | 'optionalCatchAll' }[] {\n const params: {\n name: string;\n type: 'dynamic' | 'catchAll' | 'optionalCatchAll';\n }[] = [];\n for (const match of routePath.matchAll(/\\[\\[\\.\\.\\.([^\\]]+)\\]\\]/g)) {\n params.push({ name: match[1], type: 'optionalCatchAll' });\n }\n for (const match of routePath.matchAll(/(?<!\\[)\\[\\.\\.\\.([^\\]]+)\\](?!\\])/g)) {\n params.push({ name: match[1], type: 'catchAll' });\n }\n for (const match of routePath.matchAll(/(?<!\\[)\\[(?!\\.)([^\\]]+)\\](?!\\])/g)) {\n params.push({ name: match[1], type: 'dynamic' });\n }\n return params;\n}\n\n/**\n * When `strictRouteParams` is enabled, warns if expected params from the\n * `_from` pattern are missing from the active `ActivatedRoute`.\n */\nfunction assertRouteMatch(\n from: string,\n route: ActivatedRoute,\n kind: 'injectParams' | 'injectQuery',\n): void {\n const expectedParams = extractRouteParams(from)\n .filter((param) => param.type === 'dynamic' || param.type === 'catchAll')\n .map((param) => param.name);\n\n if (expectedParams.length === 0) return;\n\n route.params.pipe(take(1)).subscribe((params) => {\n for (const name of expectedParams) {\n if (!(name in params)) {\n console.warn(\n `[Analog] ${kind}('${from}'): expected param \"${name}\" ` +\n `is not present in the active route's params. ` +\n `Ensure this hook is used inside a component rendered by '${from}'.`,\n );\n break;\n }\n }\n });\n}\n\n/**\n * Injects typed route params as a signal, constrained by the route table.\n *\n * Inspired by TanStack Router's `useParams({ from: '/users/$userId' })`\n * pattern where the `from` parameter narrows the return type to only\n * the params defined for that route.\n *\n * The `from` parameter is used purely for TypeScript type inference —\n * at runtime, params are read from the current `ActivatedRoute`. This\n * means it works correctly when used inside a component rendered by\n * the specified route.\n *\n * When `withTypedRouter({ strictRouteParams: true })` is configured,\n * a dev-mode assertion checks that the expected params from `from`\n * exist in the active route and warns on mismatch.\n *\n * @example\n * ```ts\n * // In a component rendered at /users/[id]\n * const params = injectParams('/users/[id]');\n * // params() → { id: string }\n *\n * // With schema validation output types\n * const params = injectParams('/products/[slug]');\n * // params() → validated output type from routeParamsSchema\n * ```\n *\n * @experimental\n */\nexport function injectParams<P extends AnalogRoutePath>(\n _from: P,\n options?: { injector?: Injector },\n): Signal<RouteParamsOutput<P>> {\n const injector = options?.injector;\n const route = injector\n ? injector.get(ActivatedRoute)\n : inject(ActivatedRoute);\n\n if (isDevMode()) {\n const config = injector\n ? injector.get(EXPERIMENTAL_TYPED_ROUTER, null)\n : inject(EXPERIMENTAL_TYPED_ROUTER, { optional: true });\n\n if (config?.strictRouteParams) {\n assertRouteMatch(_from, route, 'injectParams');\n }\n }\n\n return toSignal(\n route.params.pipe(map((params) => params as RouteParamsOutput<P>)),\n { requireSync: true },\n );\n}\n\n/**\n * Injects typed route query params as a signal, constrained by the\n * route table.\n *\n * Inspired by TanStack Router's `useSearch({ from: '/issues' })` pattern\n * where search params are validated and typed per-route via\n * `validateSearch` schemas.\n *\n * In Analog, the typing comes from `routeQuerySchema` exports that are\n * detected at build time and recorded in the generated route table.\n *\n * The `from` parameter is used purely for TypeScript type inference.\n * When `withTypedRouter({ strictRouteParams: true })` is configured,\n * a dev-mode assertion checks that the expected params from `from`\n * exist in the active route and warns on mismatch.\n *\n * @example\n * ```ts\n * // In a component rendered at /issues\n * // (where routeQuerySchema validates { page: number, status: string })\n * const query = injectQuery('/issues');\n * // query() → { page: number; status: string }\n * ```\n *\n * @experimental\n */\nexport function injectQuery<P extends AnalogRoutePath>(\n _from: P,\n options?: { injector?: Injector },\n): Signal<RouteQueryOutput<P>> {\n const injector = options?.injector;\n const route = injector\n ? injector.get(ActivatedRoute)\n : inject(ActivatedRoute);\n\n if (isDevMode()) {\n const config = injector\n ? injector.get(EXPERIMENTAL_TYPED_ROUTER, null)\n : inject(EXPERIMENTAL_TYPED_ROUTER, { optional: true });\n\n if (config?.strictRouteParams) {\n assertRouteMatch(_from, route, 'injectQuery');\n }\n }\n\n return toSignal(\n route.queryParams.pipe(map((params) => params as RouteQueryOutput<P>)),\n { requireSync: true },\n );\n}\n","import { inject } from '@angular/core';\n\nimport { EXPERIMENTAL_ROUTE_CONTEXT } from './experimental';\n\n/**\n * Injects the root route context provided via `withRouteContext()`.\n *\n * Inspired by TanStack Router's context inheritance where\n * `createRootRouteWithContext<T>()` makes a typed context available\n * to every route's `beforeLoad` and `loader` callbacks.\n *\n * In Angular, this uses DI under the hood — `withRouteContext(ctx)`\n * provides the value, and `injectRouteContext<T>()` retrieves it\n * with the expected type.\n *\n * @example\n * ```ts\n * // app.config.ts\n * provideFileRouter(\n * withRouteContext({\n * auth: inject(AuthService),\n * analytics: inject(AnalyticsService),\n * }),\n * )\n *\n * // any-page.page.ts\n * const ctx = injectRouteContext<{\n * auth: AuthService;\n * analytics: AnalyticsService;\n * }>();\n * ctx.analytics.trackPageView();\n * ```\n *\n * @experimental\n */\nexport function injectRouteContext<\n T extends Record<string, unknown> = Record<string, unknown>,\n>(): T {\n return inject(EXPERIMENTAL_ROUTE_CONTEXT) as T;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"analogjs-router.mjs","names":[],"sources":["../../src/lib/define-route.ts","../../src/lib/cookie-interceptor.ts","../../src/lib/provide-file-router.ts","../../src/lib/inject-load.ts","../../src/lib/get-load-resolver.ts","../../src/lib/cache-key.ts","../../src/lib/request-context.ts","../../src/lib/form-action.directive.ts","../../src/lib/debug/index.ts","../../src/lib/server.component.ts","../../src/lib/validation-errors.ts","../../src/lib/route-path.ts","../../src/lib/inject-navigate.ts","../../src/lib/experimental.ts","../../src/lib/inject-typed-params.ts","../../src/lib/inject-route-context.ts"],"sourcesContent":["import { inject } from '@angular/core';\nimport { Route as NgRoute, Router } from '@angular/router';\nimport { ActivatedRoute } from '@angular/router';\n\nimport { AnalogJsonLdDocument } from './json-ld';\nimport { MetaTag } from './meta-tags';\n\ntype RouteOmitted =\n | 'component'\n | 'loadComponent'\n | 'loadChildren'\n | 'path'\n | 'pathMatch';\n\ntype RestrictedRoute = Omit<NgRoute, RouteOmitted> & {\n meta?: MetaTag[];\n jsonLd?: AnalogJsonLdDocument;\n};\n\n/**\n * @deprecated Use `RouteMeta` type instead.\n * For more info see: https://github.com/analogjs/analog/issues/223\n *\n * Defines additional route config metadata. This\n * object is merged into the route config with\n * the predefined file-based route.\n *\n * @usageNotes\n *\n * ```\n * import { Component } from '@angular/core';\n * import { defineRouteMeta } from '@analogjs/router';\n *\n * export const routeMeta = defineRouteMeta({\n * title: 'Welcome'\n * });\n *\n * @Component({\n * template: `Home`,\n * standalone: true,\n * })\n * export default class HomeComponent {}\n * ```\n *\n * @param route\n * @returns\n */\nexport const defineRouteMeta = (route: RestrictedRoute): RestrictedRoute => {\n return route;\n};\n\n/**\n * Returns the instance of Angular Router\n *\n * @returns The router\n */\nexport const injectRouter = (): Router => {\n return inject(Router);\n};\n\n/**\n * Returns the instance of the Activate Route for the component\n *\n * @returns The activated route\n */\nexport const injectActivatedRoute = (): ActivatedRoute => {\n return inject(ActivatedRoute);\n};\n","import { isPlatformServer } from '@angular/common';\nimport {\n HttpHandlerFn,\n HttpHeaders,\n HttpRequest,\n HttpEvent,\n} from '@angular/common/http';\nimport { PLATFORM_ID, inject } from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { injectRequest, ServerRequest } from '@analogjs/router/tokens';\n\nexport function cookieInterceptor(\n req: HttpRequest<unknown>,\n next: HttpHandlerFn,\n location: object = inject(PLATFORM_ID),\n serverRequest: ServerRequest | null = injectRequest(),\n): Observable<HttpEvent<unknown>> {\n if (isPlatformServer(location) && req.url.includes('/_analog/')) {\n let headers = new HttpHeaders();\n const cookies = serverRequest?.headers.cookie;\n headers = headers.set('cookie', cookies ?? '');\n\n const cookiedRequest = req.clone({\n headers,\n });\n\n return next(cookiedRequest);\n } else {\n return next(req);\n }\n}\n","import {\n ENVIRONMENT_INITIALIZER,\n EnvironmentProviders,\n makeEnvironmentProviders,\n} from '@angular/core';\nimport { provideRouter, RouterFeatures, ROUTES, Routes } from '@angular/router';\nimport { API_PREFIX } from '@analogjs/router/tokens';\nimport { ɵHTTP_ROOT_INTERCEPTOR_FNS as HTTP_ROOT_INTERCEPTOR_FNS } from '@angular/common/http';\n\nimport { routes } from './routes';\nimport { updateJsonLdOnRouteChange } from './json-ld';\nimport { updateMetaTagsOnRouteChange } from './meta-tags';\nimport { cookieInterceptor } from './cookie-interceptor';\n\ndeclare const ANALOG_API_PREFIX: string;\n\n/**\n * Sets up providers for the Angular router, and registers\n * file-based routes. Additional features can be provided\n * to further configure the behavior of the router.\n *\n * @param features\n * @returns Providers and features to configure the router with routes\n */\nexport function provideFileRouter(\n ...features: RouterFeatures[]\n): EnvironmentProviders {\n const extraRoutesFeature = features.filter((feat) => feat.ɵkind >= 100);\n const routerFeatures = features.filter((feat) => feat.ɵkind < 100);\n\n return makeEnvironmentProviders([\n extraRoutesFeature.map((erf) => erf.ɵproviders),\n provideRouter(routes, ...routerFeatures),\n {\n provide: ENVIRONMENT_INITIALIZER,\n multi: true,\n useValue: () => updateMetaTagsOnRouteChange(),\n },\n {\n provide: ENVIRONMENT_INITIALIZER,\n multi: true,\n useValue: () => updateJsonLdOnRouteChange(),\n },\n {\n provide: HTTP_ROOT_INTERCEPTOR_FNS,\n multi: true,\n useValue: cookieInterceptor,\n },\n {\n provide: API_PREFIX,\n useFactory() {\n return typeof ANALOG_API_PREFIX !== 'undefined'\n ? ANALOG_API_PREFIX\n : 'api';\n },\n },\n ]);\n}\n\n/**\n * Provides extra custom routes in addition to the routes\n * discovered from the filesystem-based routing. These routes are\n * inserted before the filesystem-based routes, and take priority in\n * route matching.\n */\nexport function withExtraRoutes(routes: Routes): RouterFeatures {\n return {\n ɵkind: 100 as number,\n ɵproviders: [{ provide: ROUTES, useValue: routes, multi: true }],\n };\n}\n","import { Injector, inject } from '@angular/core';\nimport { ActivatedRoute, Data } from '@angular/router';\nimport { Observable, map } from 'rxjs';\n\nimport { LoadDataResult, PageServerLoad } from './route-types';\n\nfunction isResponse(value: unknown): value is Response {\n return typeof value === 'object' && value instanceof Response;\n}\n\nexport function injectLoad<\n T extends (pageServerLoad: PageServerLoad) => Promise<any>,\n>(options?: { injector?: Injector }): Observable<Awaited<ReturnType<T>>> {\n const injector = options?.injector ?? inject(Injector);\n const route = injector.get(ActivatedRoute);\n\n return route.data.pipe(\n map<Data, Awaited<ReturnType<T>>>((data) => data['load']),\n );\n}\n\nexport function injectLoadData<\n T extends (pageServerLoad: PageServerLoad) => Promise<any>,\n>(options?: { injector?: Injector }): Observable<LoadDataResult<T>> {\n return injectLoad<T>(options).pipe(\n map((result): LoadDataResult<T> => {\n if (isResponse(result)) {\n throw new Error('Expected page load data but received a response.');\n }\n\n return result as LoadDataResult<T>;\n }),\n );\n}\n","import { ActivatedRouteSnapshot } from '@angular/router';\n\n/**\n * Get server load resolver data for the route\n *\n * @param route Provides the route to get server load resolver\n * @returns Returns server load resolver data for the route\n */\nexport async function getLoadResolver<T>(\n route: ActivatedRouteSnapshot,\n): Promise<T> {\n return route.routeConfig?.resolve?.['load']?.(route);\n}\n","import { HttpParams, HttpRequest } from '@angular/common/http';\nimport { StateKey, makeStateKey } from '@angular/core';\n\nfunction sortAndConcatParams(params: HttpParams | URLSearchParams): string {\n return [...params.keys()]\n .sort()\n .map((k) => `${k}=${params.getAll(k)}`)\n .join('&');\n}\n\nexport function makeCacheKey(\n request: HttpRequest<any>,\n mappedRequestUrl: string,\n): StateKey<unknown> {\n // make the params encoded same as a url so it's easy to identify\n const { params, method, responseType } = request;\n const encodedParams = sortAndConcatParams(params);\n\n let serializedBody = request.serializeBody();\n if (serializedBody instanceof URLSearchParams) {\n serializedBody = sortAndConcatParams(serializedBody);\n } else if (typeof serializedBody !== 'string') {\n serializedBody = '';\n }\n\n const key = [\n method,\n responseType,\n mappedRequestUrl,\n serializedBody,\n encodedParams,\n ].join('|');\n\n const hash = generateHash(key);\n\n return makeStateKey(hash);\n}\n\nfunction generateHash(str: string) {\n let hash = 0;\n for (let i = 0, len = str.length; i < len; i++) {\n const chr = str.charCodeAt(i);\n hash = (hash << 5) - hash + chr;\n hash |= 0; // Convert to 32bit integer\n }\n return `${hash}`;\n}\n","import { TransferState, inject, makeStateKey } from '@angular/core';\nimport {\n HttpEvent,\n HttpHandlerFn,\n HttpHeaders,\n HttpRequest,\n HttpResponse,\n} from '@angular/common/http';\n\nimport { from, Observable, of } from 'rxjs';\n\nimport {\n injectBaseURL,\n injectAPIPrefix,\n injectInternalServerFetch,\n} from '@analogjs/router/tokens';\n\nimport { makeCacheKey } from './cache-key';\n\n/**\n * Interceptor that is server-aware when making HttpClient requests.\n * Server-side requests use the full URL\n * Prerendering uses the internal Nitro $fetch function, along with state transfer\n * Client-side requests use the window.location.origin\n *\n * @param req HttpRequest<unknown>\n * @param next HttpHandlerFn\n * @returns\n */\nexport function requestContextInterceptor(\n req: HttpRequest<unknown>,\n next: HttpHandlerFn,\n): Observable<HttpEvent<unknown>> {\n const apiPrefix = injectAPIPrefix();\n const baseUrl = injectBaseURL();\n const transferState = inject(TransferState);\n const nitroGlobal = globalThis as typeof globalThis & { $fetch?: any };\n const internalFetch = injectInternalServerFetch();\n const serverFetch = internalFetch ?? nitroGlobal.$fetch;\n\n // during prerendering with Nitro\n if (\n serverFetch &&\n baseUrl &&\n (req.url.startsWith('/') ||\n req.url.startsWith(baseUrl) ||\n req.url.startsWith(`/${apiPrefix}`))\n ) {\n const requestUrl = new URL(req.url, baseUrl);\n const cacheKey = makeCacheKey(req, new URL(requestUrl).pathname);\n const storeKey = makeStateKey<unknown>(`analog_${cacheKey}`);\n const fetchUrl = requestUrl.pathname;\n\n const responseType =\n req.responseType === 'arraybuffer' ? 'arrayBuffer' : req.responseType;\n\n return from<Promise<HttpResponse<unknown>>>(\n serverFetch\n .raw(fetchUrl, {\n method: req.method as any,\n body: req.body ? req.body : undefined,\n params: requestUrl.searchParams,\n responseType,\n headers: req.headers\n .keys()\n .reduce((hdrs: Record<string, string | null>, current: string) => {\n return {\n ...hdrs,\n [current]: req.headers.get(current),\n };\n }, {}),\n })\n .then((res: any) => {\n const cacheResponse = {\n body: res._data,\n headers: new HttpHeaders(res.headers),\n status: res.status ?? 200,\n statusText: res.statusText ?? 'OK',\n url: fetchUrl,\n };\n const transferResponse = new HttpResponse(cacheResponse);\n\n transferState.set(storeKey, cacheResponse);\n return transferResponse;\n }),\n );\n }\n\n // on the client\n if (\n !import.meta.env.SSR &&\n (req.url.startsWith('/') || req.url.includes('/_analog/'))\n ) {\n // /_analog/ requests are full URLs\n const requestUrl = req.url.includes('/_analog/')\n ? req.url\n : `${window.location.origin}${req.url}`;\n const cacheKey = makeCacheKey(req, new URL(requestUrl).pathname);\n const storeKey = makeStateKey<unknown>(`analog_${cacheKey}`);\n const cacheRestoreResponse = transferState.get(storeKey, null);\n\n if (cacheRestoreResponse) {\n transferState.remove(storeKey);\n return of(new HttpResponse(cacheRestoreResponse));\n }\n\n return next(\n req.clone({\n url: requestUrl,\n }),\n );\n }\n\n // on the server\n if (baseUrl && (req.url.startsWith('/') || req.url.startsWith(baseUrl))) {\n const requestUrl =\n req.url.startsWith(baseUrl) && !req.url.startsWith('/')\n ? req.url\n : `${baseUrl}${req.url}`;\n\n return next(\n req.clone({\n url: requestUrl,\n }),\n );\n }\n\n return next(req);\n}\n","import {\n Directive,\n inject,\n input,\n output,\n signal,\n type InputSignal,\n type OutputEmitterRef,\n type WritableSignal,\n} from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\n\nimport { injectRouteEndpointURL } from './inject-route-endpoint-url';\n\nexport type FormActionState =\n | 'submitting'\n | 'error'\n | 'redirect'\n | 'success'\n | 'navigate';\n\n@Directive({\n // eslint-disable-next-line @angular-eslint/directive-selector\n selector: 'form[action],form[method]',\n host: {\n '(submit)': `submitted($event)`,\n '[attr.data-state]': 'currentState()',\n '[attr.aria-busy]': 'currentState() === \"submitting\" ? \"true\" : null',\n },\n standalone: true,\n})\nexport class FormAction {\n action: InputSignal<string> = input<string>('');\n // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n onSuccess: OutputEmitterRef<unknown> = output<unknown>();\n // eslint-disable-next-line @angular-eslint/no-output-on-prefix\n onError: OutputEmitterRef<unknown> = output<unknown>();\n state: OutputEmitterRef<FormActionState> = output<FormActionState>();\n private router = inject(Router);\n private route = inject(ActivatedRoute);\n protected currentState: WritableSignal<FormActionState | 'idle'> = signal<\n FormActionState | 'idle'\n >('idle');\n /** Cached during construction (injection context) so inject() works. */\n private _endpointUrl = this.route\n ? injectRouteEndpointURL(this.route.snapshot)\n : undefined;\n\n submitted($event: any): void {\n $event.preventDefault();\n\n const form = $event.target as HTMLFormElement;\n this._emitState('submitting');\n const body = new FormData(form);\n\n if (form.method.toUpperCase() === 'GET') {\n this._handleGet(body, this._getGetPath(form));\n } else {\n this._handlePost(body, this._getPostPath(form), form.method);\n }\n }\n\n private _handleGet(body: FormData, path: string) {\n const url = new URL(path, window.location.href);\n const params = new URLSearchParams(url.search);\n body.forEach((value, key) => {\n params.append(key, value instanceof File ? value.name : value);\n });\n url.search = params.toString();\n\n this._emitState('navigate');\n this._navigateTo(url);\n }\n\n private _handlePost(body: FormData, path: string, method: string) {\n fetch(path, {\n method,\n body,\n })\n .then((res) => {\n if (res.ok) {\n if (res.redirected) {\n this._emitState('redirect');\n this._navigateTo(new URL(res.url, window.location.href));\n } else if (this._isJSON(res.headers.get('Content-type'))) {\n res.json().then((result) => {\n this.onSuccess.emit(result);\n this._emitState('success');\n });\n } else {\n res.text().then((result) => {\n this.onSuccess.emit(result);\n this._emitState('success');\n });\n }\n } else {\n if (res.headers.get('X-Analog-Errors')) {\n res.json().then((errors: unknown) => {\n this.onError.emit(errors);\n this._emitState('error');\n });\n } else {\n this._emitState('error');\n }\n }\n })\n .catch((_) => {\n this._emitState('error');\n });\n }\n\n private _getExplicitAction(form: HTMLFormElement) {\n const explicitAction =\n this.action().trim() || form.getAttribute('action')?.trim();\n return explicitAction || undefined;\n }\n\n private _getGetPath(form: HTMLFormElement) {\n return this._getExplicitAction(form) ?? this.router.url;\n }\n\n private _getPostPath(form: HTMLFormElement) {\n const explicitAction = this._getExplicitAction(form);\n if (explicitAction) {\n return new URL(explicitAction, window.location.href).toString();\n }\n\n if (this._endpointUrl) {\n return this._endpointUrl.pathname;\n }\n\n return `/api/_analog/pages${window.location.pathname}`;\n }\n\n private _emitState(state: FormActionState) {\n this.currentState.set(state);\n this.state.emit(state);\n }\n\n private _navigateTo(url: URL) {\n if (url.origin === window.location.origin) {\n void this.router.navigateByUrl(\n `${url.pathname}${url.search}${url.hash}`,\n {\n onSameUrlNavigation: 'reload',\n },\n );\n return;\n }\n\n window.location.assign(url.toString());\n }\n\n private _isJSON(contentType: string | null): boolean {\n const mime = contentType ? contentType.split(';') : [];\n const essence = mime[0];\n\n return essence === 'application/json';\n }\n}\n","import { EnvironmentProviders, Provider } from '@angular/core';\nimport { ROUTES } from '@angular/router';\n\n/**\n * Provides routes that provide additional\n * pages for displaying and debugging\n * routes.\n */\nexport function withDebugRoutes(): {\n ɵkind: number;\n ɵproviders: (Provider | EnvironmentProviders)[];\n} {\n const routes = [\n {\n path: '__analog/routes',\n loadComponent: () => import('./debug.page'),\n },\n ];\n\n return {\n ɵkind: 101 as number,\n ɵproviders: [{ provide: ROUTES, useValue: routes, multi: true }],\n };\n}\n","import {\n HttpClient,\n HttpHeaders,\n HttpRequest,\n HttpResponse,\n} from '@angular/common/http';\nimport {\n ChangeDetectionStrategy,\n Component,\n effect,\n inject,\n input,\n InputSignal,\n makeStateKey,\n output,\n OutputEmitterRef,\n signal,\n TransferState,\n WritableSignal,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { ActivatedRoute } from '@angular/router';\nimport { injectBaseURL } from '@analogjs/router/tokens';\nimport { catchError, map, of, throwError } from 'rxjs';\n\nimport { makeCacheKey } from './cache-key';\n\ntype ServerProps = Record<string, any>;\ntype ServerOutputs = Record<string, any>;\n\n/**\n * @description\n * Component that defines the bridge between the client and server-only\n * components. The component passes the component ID and props to the server\n * and retrieves the rendered HTML and outputs from the server-only component.\n *\n * Status: experimental\n */\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'server-only,ServerOnly,Server',\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: ` <div [innerHTML]=\"content()\"></div> `,\n})\nexport class ServerOnly {\n component: InputSignal<string> = input.required<string>();\n props: InputSignal<ServerProps | undefined> = input<ServerProps>();\n outputs: OutputEmitterRef<ServerOutputs> = output<ServerOutputs>();\n private http: HttpClient = inject(HttpClient);\n private sanitizer: DomSanitizer = inject(DomSanitizer);\n protected content: WritableSignal<SafeHtml> = signal<SafeHtml>('');\n private route: ActivatedRoute | null = inject(ActivatedRoute, {\n optional: true,\n });\n private baseURL: string | null = injectBaseURL();\n private transferState = inject(TransferState);\n\n constructor() {\n effect(() => {\n const routeComponentId: string | undefined =\n this.route?.snapshot.data['component'];\n const props = this.props() || {};\n const componentId = routeComponentId || this.component();\n\n const headers = new HttpHeaders(\n new Headers({\n 'Content-type': 'application/json',\n 'X-Analog-Component': componentId,\n }),\n );\n\n const componentUrl = this.getComponentUrl(componentId);\n const httpRequest = new HttpRequest('POST', componentUrl, props, {\n headers,\n });\n const cacheKey = makeCacheKey(\n httpRequest,\n new URL(componentUrl).pathname,\n );\n const storeKey = makeStateKey<{ html: string; outputs: ServerOutputs }>(\n cacheKey,\n );\n const componentState = this.transferState.get<{\n html: string;\n outputs: ServerOutputs;\n } | null>(storeKey, null);\n\n if (componentState) {\n this.updateContent(componentState);\n this.transferState.remove(storeKey);\n } else {\n this.http\n .request(httpRequest)\n .pipe(\n map((response) => {\n if (response instanceof HttpResponse) {\n if (import.meta.env.SSR) {\n this.transferState.set(storeKey, response.body);\n }\n\n return response.body as {\n html: string;\n outputs: ServerOutputs;\n };\n }\n return throwError(\n () => ({}) as { html: string; outputs: ServerOutputs },\n );\n }),\n catchError((error: unknown) => {\n console.log(error);\n return of({\n html: '',\n outputs: {} as ServerOutputs,\n });\n }),\n )\n .subscribe((content) =>\n this.updateContent(\n content as { html: string; outputs: ServerOutputs },\n ),\n );\n }\n });\n }\n\n updateContent(content: { html: string; outputs: ServerOutputs }): void {\n this.content.set(this.sanitizer.bypassSecurityTrustHtml(content.html));\n this.outputs.emit(content.outputs);\n }\n\n getComponentUrl(componentId: string) {\n let baseURL = this.baseURL;\n\n if (!baseURL && typeof window !== 'undefined') {\n baseURL = window.location.origin;\n }\n\n return `${baseURL}/_analog/components/${componentId}`;\n }\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\n\nexport type ValidationFieldErrors = Record<string, string[]>;\n\nfunction getPathSegmentKey(\n segment: string | number | symbol | { key: string | number | symbol },\n) {\n return typeof segment === 'object' ? segment.key : segment;\n}\n\nexport function issuePathToFieldName(\n path: ReadonlyArray<\n string | number | symbol | { key: string | number | symbol }\n >,\n): string {\n return path.map((segment) => String(getPathSegmentKey(segment))).join('.');\n}\n\nexport function issuesToFieldErrors(\n issues: ReadonlyArray<StandardSchemaV1.Issue>,\n): ValidationFieldErrors {\n return issues.reduce<ValidationFieldErrors>((errors, issue) => {\n if (!issue.path?.length) {\n return errors;\n }\n\n const fieldName = issuePathToFieldName(issue.path);\n errors[fieldName] ??= [];\n errors[fieldName].push(issue.message);\n return errors;\n }, {});\n}\n\nexport function issuesToFormErrors(\n issues: ReadonlyArray<StandardSchemaV1.Issue>,\n): string[] {\n return issues\n .filter((issue) => !issue.path?.length)\n .map((issue) => issue.message);\n}\n","/**\n * Typed route path utilities for Analog.\n *\n * This module provides:\n * - The `AnalogRouteTable` base interface (augmented by generated code)\n * - The `AnalogRoutePath` union type\n * - The `routePath()` URL builder function\n *\n * No Angular dependencies — can be used in any context.\n */\n\n/**\n * Base interface for the typed route table.\n *\n * This interface is augmented by generated code in `src/routeTree.gen.ts`.\n * When no routes are generated, it is empty and `AnalogRoutePath` falls\n * back to `string`.\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type\nexport interface AnalogRouteTable {}\n\n/**\n * Union of all valid route paths.\n *\n * When routes are generated, this is a string literal union.\n * When no routes are generated, this falls back to `string`.\n */\nexport type AnalogRoutePath = keyof AnalogRouteTable extends never\n ? string\n : Extract<keyof AnalogRouteTable, string>;\n\n/**\n * Options for building a route URL.\n */\nexport interface RoutePathOptionsBase {\n params?: Record<string, string | string[] | undefined>;\n query?: Record<string, string | string[] | undefined>;\n hash?: string;\n}\n\n/**\n * Extracts the validated output type for route params.\n *\n * When a route exports `routeParamsSchema`, this resolves to the schema's\n * output type (e.g., `{ id: number }` after coercion).\n * When no schema exists, this is the same as the navigation param type.\n */\nexport type RouteParamsOutput<P extends string> =\n P extends keyof AnalogRouteTable\n ? AnalogRouteTable[P] extends { paramsOutput: infer O }\n ? O\n : AnalogRouteTable[P] extends { params: infer Params }\n ? Params\n : Record<string, unknown>\n : Record<string, unknown>;\n\n/**\n * Extracts the validated output type for route query params.\n */\nexport type RouteQueryOutput<P extends string> =\n P extends keyof AnalogRouteTable\n ? AnalogRouteTable[P] extends { queryOutput: infer O }\n ? O\n : Record<string, string | string[] | undefined>\n : Record<string, string | string[] | undefined>;\n\ntype RequiredRouteParamKeys<Params> =\n Params extends Record<string, never>\n ? never\n : {\n [K in keyof Params]-?: Record<string, never> extends Pick<Params, K>\n ? never\n : K;\n }[keyof Params];\n\ntype HasRequiredRouteParams<Params> = [RequiredRouteParamKeys<Params>] extends [\n never,\n]\n ? false\n : true;\n\n/**\n * Typed options that infer params from the route table when available.\n */\nexport type RoutePathOptions<P extends string = string> =\n P extends keyof AnalogRouteTable\n ? AnalogRouteTable[P] extends { params: infer Params }\n ? Params extends Record<string, never>\n ? {\n query?: RouteQueryOutput<P>;\n hash?: string;\n }\n : HasRequiredRouteParams<Params> extends true\n ? {\n params: Params;\n query?: RouteQueryOutput<P>;\n hash?: string;\n }\n : {\n params?: Params;\n query?: RouteQueryOutput<P>;\n hash?: string;\n }\n : RoutePathOptionsBase\n : RoutePathOptionsBase;\n\n/**\n * Conditional args: require options when the route has params.\n */\nexport type RoutePathArgs<P extends string = string> =\n P extends keyof AnalogRouteTable\n ? AnalogRouteTable[P] extends { params: infer Params }\n ? Params extends Record<string, never>\n ? [options?: RoutePathOptions<P>]\n : HasRequiredRouteParams<Params> extends true\n ? [options: RoutePathOptions<P>]\n : [options?: RoutePathOptions<P>]\n : [options?: RoutePathOptionsBase]\n : [options?: RoutePathOptionsBase];\n\n/**\n * Result of `routePath()` — contains properties that map directly\n * to Angular's `[routerLink]`, `[queryParams]`, and `[fragment]` inputs.\n */\nexport interface RouteLinkResult {\n path: string;\n queryParams: Record<string, string | string[]> | null;\n fragment: string | undefined;\n}\n\n/**\n * Builds a typed route link object from a route path pattern and options.\n *\n * The returned object separates path, query params, and fragment for\n * direct use with Angular's routerLink directive inputs.\n *\n * @example\n * routePath('/about')\n * // → { path: '/about', queryParams: null, fragment: undefined }\n *\n * routePath('/users/[id]', { params: { id: '42' } })\n * // → { path: '/users/42', queryParams: null, fragment: undefined }\n *\n * routePath('/users/[id]', { params: { id: '42' }, query: { tab: 'settings' }, hash: 'bio' })\n * // → { path: '/users/42', queryParams: { tab: 'settings' }, fragment: 'bio' }\n *\n * @example Template usage\n * ```html\n * @let link = routePath('/users/[id]', { params: { id: userId } });\n * <a [routerLink]=\"link.path\" [queryParams]=\"link.queryParams\" [fragment]=\"link.fragment\">\n * ```\n */\nexport function routePath<P extends AnalogRoutePath>(\n path: P,\n ...args: RoutePathArgs<P>\n): RouteLinkResult {\n const options = args[0] as RoutePathOptionsBase | undefined;\n return buildRouteLink(path as string, options);\n}\n\n/**\n * Internal: builds a `RouteLinkResult` from path and options.\n * Exported for direct use in tests (avoids generic constraints).\n */\nexport function buildRouteLink(\n path: string,\n options?: RoutePathOptionsBase,\n): RouteLinkResult {\n const resolvedPath = buildPath(path, options?.params);\n\n let queryParams: Record<string, string | string[]> | null = null;\n if (options?.query) {\n const filtered: Record<string, string | string[]> = {};\n let hasEntries = false;\n for (const [key, value] of Object.entries(options.query)) {\n if (value !== undefined) {\n filtered[key] = value;\n hasEntries = true;\n }\n }\n if (hasEntries) {\n queryParams = filtered;\n }\n }\n\n return {\n path: resolvedPath,\n queryParams,\n fragment: options?.hash,\n };\n}\n\n/**\n * Resolves param placeholders and normalises slashes.\n * Returns only the path — no query string or hash.\n */\nfunction buildPath(\n path: string,\n params?: Record<string, string | string[] | undefined>,\n): string {\n let url = path;\n\n if (params) {\n // Replace [[...param]] — optional catch-all\n url = url.replace(/\\[\\[\\.\\.\\.([^\\]]+)\\]\\]/g, (_, name) => {\n const value = params[name];\n if (value == null) return '';\n if (Array.isArray(value)) {\n return value.map((v) => encodeURIComponent(v)).join('/');\n }\n return encodeURIComponent(String(value));\n });\n\n // Replace [...param] — required catch-all\n url = url.replace(/\\[\\.\\.\\.([^\\]]+)\\]/g, (_, name) => {\n const value = params[name];\n if (value == null) {\n throw new Error(\n `Missing required catch-all param \"${name}\" for path \"${path}\"`,\n );\n }\n if (Array.isArray(value)) {\n if (value.length === 0) {\n throw new Error(\n `Missing required catch-all param \"${name}\" for path \"${path}\"`,\n );\n }\n return value.map((v) => encodeURIComponent(v)).join('/');\n }\n return encodeURIComponent(String(value));\n });\n\n // Replace [param] — dynamic param\n url = url.replace(/\\[([^\\]]+)\\]/g, (_, name) => {\n const value = params[name];\n if (value == null) {\n throw new Error(`Missing required param \"${name}\" for path \"${path}\"`);\n }\n return encodeURIComponent(String(value));\n });\n } else {\n // Strip bracket syntax when no params provided\n url = url.replace(/\\[\\[\\.\\.\\.([^\\]]+)\\]\\]/g, '');\n url = url.replace(/\\[\\.\\.\\.([^\\]]+)\\]/g, '');\n url = url.replace(/\\[([^\\]]+)\\]/g, '');\n }\n\n // Clean up double/trailing slashes\n url = url.replace(/\\/+/g, '/');\n if (url.length > 1 && url.endsWith('/')) {\n url = url.slice(0, -1);\n }\n if (!url.startsWith('/')) {\n url = '/' + url;\n }\n\n return url;\n}\n\n/**\n * Internal URL builder. Separated from `routePath` so it can be\n * used without generic constraints (e.g., in `injectNavigate`).\n */\nexport function buildUrl(path: string, options?: RoutePathOptionsBase): string {\n let url = buildPath(path, options?.params);\n\n if (options?.query) {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(options.query)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const v of value) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(v)}`);\n }\n } else {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);\n }\n }\n if (parts.length > 0) {\n url += '?' + parts.join('&');\n }\n }\n\n if (options?.hash) {\n url += '#' + options.hash;\n }\n\n return url;\n}\n","import { inject } from '@angular/core';\nimport { type NavigationBehaviorOptions, Router } from '@angular/router';\n\nimport type {\n AnalogRoutePath,\n RoutePathArgs,\n RoutePathOptionsBase,\n} from './route-path';\nimport { buildUrl } from './route-path';\n\ntype NavigateWithExtrasArgs<P extends AnalogRoutePath> =\n RoutePathArgs<P> extends [options?: infer Options]\n ?\n | [extras: NavigationBehaviorOptions]\n | [options: Options | undefined, extras: NavigationBehaviorOptions]\n : [options: RoutePathArgs<P>[0], extras: NavigationBehaviorOptions];\n\ntype TypedNavigate = {\n <P extends AnalogRoutePath>(\n path: P,\n ...args: RoutePathArgs<P>\n ): Promise<boolean>;\n <P extends AnalogRoutePath>(\n path: P,\n ...args: NavigateWithExtrasArgs<P>\n ): Promise<boolean>;\n};\n\nfunction isRoutePathOptionsBase(value: unknown): value is RoutePathOptionsBase {\n return (\n !!value &&\n typeof value === 'object' &&\n ('params' in value || 'query' in value || 'hash' in value)\n );\n}\n\n/**\n * Injects a typed navigate function.\n *\n * @example\n * ```ts\n * const navigate = injectNavigate();\n *\n * navigate('/users/[id]', { params: { id: '42' } }); // ✅\n * navigate('/users/[id]', { params: { id: 42 } }); // ❌ type error\n *\n * // With navigation extras\n * navigate('/users/[id]', { params: { id: '42' } }, { replaceUrl: true });\n * ```\n */\nexport function injectNavigate(): TypedNavigate {\n const router = inject(Router);\n\n const navigate = ((\n path: AnalogRoutePath,\n ...args: unknown[]\n ): Promise<boolean> => {\n let options: RoutePathOptionsBase | undefined;\n let extras: NavigationBehaviorOptions | undefined;\n\n if (args.length > 1) {\n options = args[0] as RoutePathOptionsBase | undefined;\n extras = args[1] as NavigationBehaviorOptions | undefined;\n } else if (args.length === 1) {\n if (isRoutePathOptionsBase(args[0])) {\n options = args[0];\n } else {\n extras = args[0] as NavigationBehaviorOptions;\n }\n }\n\n const url = buildUrl(path as string, options);\n return router.navigateByUrl(url, extras);\n }) as TypedNavigate;\n\n return navigate;\n}\n","import { InjectionToken } from '@angular/core';\nimport type { RouterFeatures } from '@angular/router';\n\n/**\n * Configuration for experimental typed router features.\n *\n * Inspired by TanStack Router's type-safe navigation system where\n * routes are registered globally and all navigation/hooks are typed\n * against the route tree.\n *\n * @experimental\n */\nexport interface TypedRouterOptions {\n /**\n * When true, logs warnings in development when navigating to\n * routes with params that don't match the generated route table.\n *\n * Similar to TanStack Router's strict mode where `useParams()`\n * without a `from` constraint returns a union of all possible params.\n *\n * @default false\n */\n strictRouteParams?: boolean;\n}\n\n/**\n * Configuration for experimental loader caching.\n *\n * Inspired by TanStack Router's built-in data caching where route\n * loaders automatically cache results and support stale-while-revalidate.\n *\n * @experimental\n */\nexport interface LoaderCacheOptions {\n /**\n * Time in milliseconds before loader data is considered stale.\n * While data is fresh, navigating back to the route uses cached\n * data without re-invoking the server load function.\n *\n * Mirrors TanStack Router's `defaultStaleTime` option on `createRouter()`.\n *\n * @default 0 (always re-fetch)\n */\n defaultStaleTime?: number;\n\n /**\n * Time in milliseconds to retain unused loader data in cache\n * after leaving a route. After this period the cached entry is\n * garbage-collected.\n *\n * Mirrors TanStack Router's `defaultGcTime` (default 30 min).\n *\n * @default 300_000 (5 minutes)\n */\n defaultGcTime?: number;\n\n /**\n * Delay in milliseconds before showing a pending/loading indicator\n * during route transitions. Prevents flash-of-loading-state for\n * fast navigations.\n *\n * Mirrors TanStack Router's `defaultPendingMs`.\n *\n * @default 0 (show immediately)\n */\n defaultPendingMs?: number;\n}\n\n// ---------------------------------------------------------------------------\n// DI tokens\n// ---------------------------------------------------------------------------\n\n/** @experimental */\nexport const EXPERIMENTAL_TYPED_ROUTER: InjectionToken<TypedRouterOptions> =\n new InjectionToken<TypedRouterOptions>('EXPERIMENTAL_TYPED_ROUTER');\n\n/** @experimental */\nexport const EXPERIMENTAL_ROUTE_CONTEXT: InjectionToken<\n Record<string, unknown>\n> = new InjectionToken<Record<string, unknown>>('EXPERIMENTAL_ROUTE_CONTEXT');\n\n/** @experimental */\nexport const EXPERIMENTAL_LOADER_CACHE: InjectionToken<LoaderCacheOptions> =\n new InjectionToken<LoaderCacheOptions>('EXPERIMENTAL_LOADER_CACHE');\n\n// ---------------------------------------------------------------------------\n// Provider feature functions (passed to provideFileRouter)\n// ---------------------------------------------------------------------------\n\n/**\n * Enables experimental typed router features.\n *\n * When active, `routePath()`, `injectNavigate()`, `injectParams()`,\n * and `injectQuery()` will enforce route table constraints and\n * optionally log warnings in strict mode.\n *\n * Inspired by TanStack Router's `Register` interface and strict type\n * checking across the entire navigation surface.\n *\n * @example\n * ```ts\n * provideFileRouter(\n * withTypedRouter({ strictRouteParams: true }),\n * )\n * ```\n *\n * @experimental\n */\nexport function withTypedRouter(options?: TypedRouterOptions): RouterFeatures {\n return {\n ɵkind: 102 as number,\n ɵproviders: [\n {\n provide: EXPERIMENTAL_TYPED_ROUTER,\n useValue: { strictRouteParams: false, ...options },\n },\n ],\n };\n}\n\n/**\n * Provides root-level route context available to all route loaders\n * and components via `injectRouteContext()`.\n *\n * Inspired by TanStack Router's `createRootRouteWithContext<T>()` where\n * a typed context object is required at router creation and automatically\n * available in every route's `beforeLoad` and `loader`.\n *\n * In Angular terms, this creates a DI token that server-side load\n * functions and components can inject to access shared services\n * without importing them individually.\n *\n * @example\n * ```ts\n * // app.config.ts\n * provideFileRouter(\n * withRouteContext({\n * auth: inject(AuthService),\n * db: inject(DatabaseService),\n * }),\n * )\n *\n * // In a component\n * const ctx = injectRouteContext<{ auth: AuthService; db: DatabaseService }>();\n * ```\n *\n * @experimental\n */\nexport function withRouteContext<T extends Record<string, unknown>>(\n context: T,\n): RouterFeatures {\n return {\n ɵkind: 103 as number,\n ɵproviders: [\n {\n provide: EXPERIMENTAL_ROUTE_CONTEXT,\n useValue: context,\n },\n ],\n };\n}\n\n/**\n * Configures experimental loader caching behavior for server-loaded\n * route data.\n *\n * Inspired by TanStack Router's built-in cache where `createRouter()`\n * accepts `defaultStaleTime` and `defaultGcTime` to control when\n * loaders re-execute and when cached data is discarded.\n *\n * @example\n * ```ts\n * provideFileRouter(\n * withLoaderCaching({\n * defaultStaleTime: 30_000, // 30s before re-fetch\n * defaultGcTime: 300_000, // 5min cache retention\n * defaultPendingMs: 200, // 200ms loading delay\n * }),\n * )\n * ```\n *\n * @experimental\n */\nexport function withLoaderCaching(\n options?: LoaderCacheOptions,\n): RouterFeatures {\n return {\n ɵkind: 104 as number,\n ɵproviders: [\n {\n provide: EXPERIMENTAL_LOADER_CACHE,\n useValue: {\n defaultStaleTime: 0,\n defaultGcTime: 300_000,\n defaultPendingMs: 0,\n ...options,\n },\n },\n ],\n };\n}\n","import { inject, Injector, isDevMode, Signal } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { map, take } from 'rxjs';\n\nimport type {\n AnalogRoutePath,\n RouteParamsOutput,\n RouteQueryOutput,\n} from './route-path';\nimport { EXPERIMENTAL_TYPED_ROUTER } from './experimental';\n\nfunction extractRouteParams(\n routePath: string,\n): { name: string; type: 'dynamic' | 'catchAll' | 'optionalCatchAll' }[] {\n const params: {\n name: string;\n type: 'dynamic' | 'catchAll' | 'optionalCatchAll';\n }[] = [];\n for (const match of routePath.matchAll(/\\[\\[\\.\\.\\.([^\\]]+)\\]\\]/g)) {\n params.push({ name: match[1], type: 'optionalCatchAll' });\n }\n for (const match of routePath.matchAll(/(?<!\\[)\\[\\.\\.\\.([^\\]]+)\\](?!\\])/g)) {\n params.push({ name: match[1], type: 'catchAll' });\n }\n for (const match of routePath.matchAll(/(?<!\\[)\\[(?!\\.)([^\\]]+)\\](?!\\])/g)) {\n params.push({ name: match[1], type: 'dynamic' });\n }\n return params;\n}\n\n/**\n * When `strictRouteParams` is enabled, warns if expected params from the\n * `_from` pattern are missing from the active `ActivatedRoute`.\n */\nfunction assertRouteMatch(\n from: string,\n route: ActivatedRoute,\n kind: 'injectParams' | 'injectQuery',\n): void {\n const expectedParams = extractRouteParams(from)\n .filter((param) => param.type === 'dynamic' || param.type === 'catchAll')\n .map((param) => param.name);\n\n if (expectedParams.length === 0) return;\n\n route.params.pipe(take(1)).subscribe((params) => {\n for (const name of expectedParams) {\n if (!(name in params)) {\n console.warn(\n `[Analog] ${kind}('${from}'): expected param \"${name}\" ` +\n `is not present in the active route's params. ` +\n `Ensure this hook is used inside a component rendered by '${from}'.`,\n );\n break;\n }\n }\n });\n}\n\n/**\n * Injects typed route params as a signal, constrained by the route table.\n *\n * Inspired by TanStack Router's `useParams({ from: '/users/$userId' })`\n * pattern where the `from` parameter narrows the return type to only\n * the params defined for that route.\n *\n * The `from` parameter is used purely for TypeScript type inference —\n * at runtime, params are read from the current `ActivatedRoute`. This\n * means it works correctly when used inside a component rendered by\n * the specified route.\n *\n * When `withTypedRouter({ strictRouteParams: true })` is configured,\n * a dev-mode assertion checks that the expected params from `from`\n * exist in the active route and warns on mismatch.\n *\n * @example\n * ```ts\n * // In a component rendered at /users/[id]\n * const params = injectParams('/users/[id]');\n * // params() → { id: string }\n *\n * // With schema validation output types\n * const params = injectParams('/products/[slug]');\n * // params() → validated output type from routeParamsSchema\n * ```\n *\n * @experimental\n */\nexport function injectParams<P extends AnalogRoutePath>(\n _from: P,\n options?: { injector?: Injector },\n): Signal<RouteParamsOutput<P>> {\n const injector = options?.injector;\n const route = injector\n ? injector.get(ActivatedRoute)\n : inject(ActivatedRoute);\n\n if (isDevMode()) {\n const config = injector\n ? injector.get(EXPERIMENTAL_TYPED_ROUTER, null)\n : inject(EXPERIMENTAL_TYPED_ROUTER, { optional: true });\n\n if (config?.strictRouteParams) {\n assertRouteMatch(_from, route, 'injectParams');\n }\n }\n\n return toSignal(\n route.params.pipe(map((params) => params as RouteParamsOutput<P>)),\n { requireSync: true },\n );\n}\n\n/**\n * Injects typed route query params as a signal, constrained by the\n * route table.\n *\n * Inspired by TanStack Router's `useSearch({ from: '/issues' })` pattern\n * where search params are validated and typed per-route via\n * `validateSearch` schemas.\n *\n * In Analog, the typing comes from `routeQuerySchema` exports that are\n * detected at build time and recorded in the generated route table.\n *\n * The `from` parameter is used purely for TypeScript type inference.\n * When `withTypedRouter({ strictRouteParams: true })` is configured,\n * a dev-mode assertion checks that the expected params from `from`\n * exist in the active route and warns on mismatch.\n *\n * @example\n * ```ts\n * // In a component rendered at /issues\n * // (where routeQuerySchema validates { page: number, status: string })\n * const query = injectQuery('/issues');\n * // query() → { page: number; status: string }\n * ```\n *\n * @experimental\n */\nexport function injectQuery<P extends AnalogRoutePath>(\n _from: P,\n options?: { injector?: Injector },\n): Signal<RouteQueryOutput<P>> {\n const injector = options?.injector;\n const route = injector\n ? injector.get(ActivatedRoute)\n : inject(ActivatedRoute);\n\n if (isDevMode()) {\n const config = injector\n ? injector.get(EXPERIMENTAL_TYPED_ROUTER, null)\n : inject(EXPERIMENTAL_TYPED_ROUTER, { optional: true });\n\n if (config?.strictRouteParams) {\n assertRouteMatch(_from, route, 'injectQuery');\n }\n }\n\n return toSignal(\n route.queryParams.pipe(map((params) => params as RouteQueryOutput<P>)),\n { requireSync: true },\n );\n}\n","import { inject } from '@angular/core';\n\nimport { EXPERIMENTAL_ROUTE_CONTEXT } from './experimental';\n\n/**\n * Injects the root route context provided via `withRouteContext()`.\n *\n * Inspired by TanStack Router's context inheritance where\n * `createRootRouteWithContext<T>()` makes a typed context available\n * to every route's `beforeLoad` and `loader` callbacks.\n *\n * In Angular, this uses DI under the hood — `withRouteContext(ctx)`\n * provides the value, and `injectRouteContext<T>()` retrieves it\n * with the expected type.\n *\n * @example\n * ```ts\n * // app.config.ts\n * provideFileRouter(\n * withRouteContext({\n * auth: inject(AuthService),\n * analytics: inject(AnalyticsService),\n * }),\n * )\n *\n * // any-page.page.ts\n * const ctx = injectRouteContext<{\n * auth: AuthService;\n * analytics: AnalyticsService;\n * }>();\n * ctx.analytics.trackPageView();\n * ```\n *\n * @experimental\n */\nexport function injectRouteContext<\n T extends Record<string, unknown> = Record<string, unknown>,\n>(): T {\n return inject(EXPERIMENTAL_ROUTE_CONTEXT) as T;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug.page.mjs","names":[],"sources":["
|
|
1
|
+
{"version":3,"file":"debug.page.mjs","names":[],"sources":["../../src/lib/debug/debug.page.ts"],"sourcesContent":["import { Component, OnInit } from '@angular/core';\n\nimport { Route } from '@angular/router';\nimport { injectDebugRoutes, DebugRoute } from './routes';\n\ntype CollectedRoute = {\n path: string;\n filename: string;\n file: string;\n isLayout: boolean;\n};\n\n@Component({\n selector: 'analogjs-debug-routes-page',\n standalone: true,\n template: `\n <h2>Routes</h2>\n\n <div class=\"table-container\">\n <div class=\"table-header\">\n <div class=\"header-cell\">Route Path</div>\n <div class=\"header-cell\">File</div>\n <div class=\"header-cell\">Type</div>\n </div>\n <div class=\"table-body\">\n @for (\n collectedRoute of collectedRoutes;\n track collectedRoute.filename\n ) {\n <div class=\"table-row\">\n <div class=\"table-cell\">{{ collectedRoute.path }}</div>\n <div class=\"table-cell\" [title]=\"collectedRoute.filename\">\n {{ collectedRoute.file }}\n </div>\n <div class=\"table-cell\">\n {{ collectedRoute.isLayout ? 'Layout' : 'Page' }}\n </div>\n </div>\n }\n </div>\n </div>\n `,\n styles: `\n :host {\n width: 100%;\n }\n\n .table-container {\n width: 100%;\n max-width: 900px;\n margin: 0 auto;\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n }\n\n .table-header {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n background: gray;\n border-bottom: 2px solid #e5e7eb;\n }\n\n .header-cell {\n padding: 16px 24px;\n font-weight: 600;\n text-transform: uppercase;\n font-size: 14px;\n letter-spacing: 0.05em;\n color: white;\n }\n\n .table-body {\n display: flex;\n flex-direction: column;\n }\n\n .table-row {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n border-bottom: 1px solid #e5e7eb;\n transition: background-color 0.2s ease;\n }\n\n .table-row:last-child {\n border-bottom: none;\n }\n\n .table-row:hover {\n background-color: #f9fafb;\n }\n\n .table-cell {\n padding: 16px 24px;\n font-size: 16px;\n color: #4b5563;\n }\n\n @media (max-width: 640px) {\n .table-container {\n border-radius: 0;\n margin: 0;\n }\n\n .header-cell,\n .table-cell {\n padding: 12px 16px;\n }\n }\n `,\n})\nexport default class DebugRoutesComponent implements OnInit {\n collectedRoutes: CollectedRoute[] = [];\n debugRoutes: (import('@angular/router').Route & DebugRoute)[] =\n injectDebugRoutes();\n\n ngOnInit(): void {\n this.traverseRoutes(this.debugRoutes);\n }\n\n traverseRoutes(routes: DebugRoute[], parent?: string): void {\n routes.forEach((route) => {\n this.collectedRoutes.push({\n path: route.isLayout\n ? `${parent ? `/${parent}` : ''}${route.path ? `/${route.path}` : ''}`\n : `${parent ? `/${parent}` : ''}${\n route.path ? `/${route.path}` : '/'\n }`,\n filename: route.filename,\n file: route.filename?.replace(/(^.*)pages\\//, '') || '',\n isLayout: route.isLayout,\n });\n\n if (route.children) {\n const parentSegments = [parent, route.path];\n\n const fullParentPath = parentSegments.filter((s) => !!s).join('/');\n this.traverseRoutes(route.children, fullParentPath);\n }\n });\n }\n}\n"],"mappings":";;;;AAgHe,IAAA,uBAAA,MAAA,qBAAM;;yBACmB,EAAA;qBAEpC,mBAAmB;;CAErB,WAAiB;AACV,OAAA,eAAoB,KAAA,YAAY;;CAGvC,eAAe,QAAsB,QAAuB;AAC1D,SAAO,SAAS,UAAU;AACnB,QAAA,gBAAqB,KAAA;IACZ,MAAA,MACR,WAIY,GAAA,SAAA,IAAA,WAAA,KAAA,MAAA,OAAA,IAAA,MAAA,SAAA,OACJ,GAAA,SAAkB,IAAA,WAAA,KAAmB,MAAI,OAAA,IAAA,MAAA,SAAA;IAC3C,UAAM,MAAA;IAChB,MAAA,MAAA,UAAA,QAAA,gBAAA,GAAA,IAAA;IAEQ,UAAU,MAAA;IACZ,CAAA;AAEA,OAAA,MAAA,UAAiB;2BACG,CAAU,QAAA,MAAA,KAAe,CAAA,QAAA,MAAA,CAAA,CAAA,EAAA,CAAA,KAAA,IAAA;AAErD,SAAA,eAAA,MAAA,UAAA,eAAA;;;;CA/HJ;AAAU,OAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAA,MAAA,EAAA;GAAA,QAAA,GAAA,gBAAA;GAAA,CAAA;;CACV;AAAY,OAAA,OAAA,GAAA,qBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,MAAA;GAAA,cAAA;GAAA,UAAA;GAAA,UAAA;GAAA,UAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BZ,yBAAQ;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAA,YAAA,CAAA"}
|
package/fesm2022/routes.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.mjs","names":[],"sources":["../../../../packages/router/src/lib/json-ld.ts","../../../../packages/router/src/lib/meta-tags.ts","../../../../packages/router/src/lib/endpoints.ts","../../../../packages/router/src/lib/inject-route-endpoint-url.ts","../../../../packages/router/src/lib/route-config.ts","../../../../packages/router/src/lib/markdown-helpers.ts","../../../../packages/router/src/lib/constants.ts","../../../../packages/router/src/lib/routes.ts","../../../../packages/router/src/lib/debug/routes.ts"],"sourcesContent":["import { DOCUMENT } from '@angular/common';\nimport { inject } from '@angular/core';\nimport { ActivatedRouteSnapshot, NavigationEnd, Router } from '@angular/router';\nimport { filter } from 'rxjs/operators';\n\nimport type { Graph, Thing, WithContext } from 'schema-dts';\n\nexport type JsonLdObject = Record<string, unknown>;\n\nexport function isJsonLdObject(value: unknown): value is JsonLdObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function normalizeJsonLd(value: unknown): JsonLdObject[] {\n if (Array.isArray(value)) {\n return value.filter(isJsonLdObject);\n }\n\n return isJsonLdObject(value) ? [value] : [];\n}\n\nexport type JsonLd = JsonLdObject | JsonLdObject[];\n\n/**\n * Typed JSON-LD document based on `schema-dts`.\n *\n * Accepts single Schema.org nodes (`WithContext<Thing>`),\n * `@graph`-based documents (`Graph`), or arrays of nodes.\n *\n * This is the canonical JSON-LD type for route authoring surfaces\n * (`routeMeta.jsonLd`, `routeJsonLd`, generated manifest).\n *\n * @example\n * ```ts\n * import type { WebPage, WithContext } from 'schema-dts';\n *\n * export const routeMeta = {\n * jsonLd: {\n * '@context': 'https://schema.org',\n * '@type': 'WebPage',\n * name: 'Products',\n * } satisfies WithContext<WebPage>,\n * };\n * ```\n */\nexport type AnalogJsonLdDocument =\n | WithContext<Thing>\n | Graph\n | Array<WithContext<Thing>>;\n\nexport const ROUTE_JSON_LD_KEY: unique symbol = Symbol(\n '@analogjs/router Route JSON-LD Key',\n);\nconst JSON_LD_SCRIPT_SELECTOR = 'script[data-analog-json-ld]';\n\nexport function updateJsonLdOnRouteChange(): void {\n const router = inject(Router);\n const document = inject(DOCUMENT);\n\n router.events\n .pipe(filter((event) => event instanceof NavigationEnd))\n .subscribe(() => {\n applyJsonLdToDocument(\n document,\n getJsonLdEntries(router.routerState.snapshot.root),\n );\n });\n}\n\nexport function serializeJsonLd(entry: JsonLdObject): string | null {\n try {\n return JSON.stringify(entry)\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e')\n .replace(/&/g, '\\\\u0026')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n } catch {\n return null;\n }\n}\n\nfunction getJsonLdEntries(route: ActivatedRouteSnapshot): JsonLdObject[] {\n const entries: JsonLdObject[] = [];\n let currentRoute: ActivatedRouteSnapshot | null = route;\n\n while (currentRoute) {\n entries.push(...normalizeJsonLd(currentRoute.data[ROUTE_JSON_LD_KEY]));\n currentRoute = currentRoute.firstChild;\n }\n\n return entries;\n}\n\nfunction applyJsonLdToDocument(\n document: Document,\n entries: JsonLdObject[],\n): void {\n document.querySelectorAll(JSON_LD_SCRIPT_SELECTOR).forEach((element) => {\n element.remove();\n });\n\n if (entries.length === 0) {\n return;\n }\n\n const head = document.head || document.getElementsByTagName('head')[0];\n if (!head) {\n return;\n }\n\n entries.forEach((entry, index) => {\n const serialized = serializeJsonLd(entry);\n if (!serialized) {\n return;\n }\n\n const script = document.createElement('script');\n script.type = 'application/ld+json';\n script.setAttribute('data-analog-json-ld', 'true');\n script.setAttribute('data-analog-json-ld-index', String(index));\n script.textContent = serialized;\n head.appendChild(script);\n });\n}\n","import { inject } from '@angular/core';\nimport { Meta, MetaDefinition as NgMetaTag } from '@angular/platform-browser';\nimport { ActivatedRouteSnapshot, NavigationEnd, Router } from '@angular/router';\nimport { filter } from 'rxjs/operators';\n\nexport const ROUTE_META_TAGS_KEY: unique symbol = Symbol(\n '@analogjs/router Route Meta Tags Key',\n);\n\nconst CHARSET_KEY = 'charset';\nconst HTTP_EQUIV_KEY = 'httpEquiv';\n// httpEquiv selector key needs to be in kebab case format\nconst HTTP_EQUIV_SELECTOR_KEY = 'http-equiv';\nconst NAME_KEY = 'name';\nconst PROPERTY_KEY = 'property';\nconst CONTENT_KEY = 'content';\nconst ITEMPROP_KEY = 'itemprop';\n\nexport type MetaTag =\n | (CharsetMetaTag & ExcludeRestMetaTagKeys<typeof CHARSET_KEY>)\n | (HttpEquivMetaTag & ExcludeRestMetaTagKeys<typeof HTTP_EQUIV_KEY>)\n | (NameMetaTag & ExcludeRestMetaTagKeys<typeof NAME_KEY>)\n | (PropertyMetaTag & ExcludeRestMetaTagKeys<typeof PROPERTY_KEY>)\n | (ItempropMetaTag & ExcludeRestMetaTagKeys<typeof ITEMPROP_KEY>);\n\ntype CharsetMetaTag = { [CHARSET_KEY]: string };\ntype HttpEquivMetaTag = { [HTTP_EQUIV_KEY]: string; [CONTENT_KEY]: string };\ntype NameMetaTag = { [NAME_KEY]: string; [CONTENT_KEY]: string };\ntype PropertyMetaTag = { [PROPERTY_KEY]: string; [CONTENT_KEY]: string };\ntype ItempropMetaTag = { [ITEMPROP_KEY]: string; [CONTENT_KEY]: string };\n\ntype MetaTagKey =\n | typeof CHARSET_KEY\n | typeof HTTP_EQUIV_KEY\n | typeof NAME_KEY\n | typeof PROPERTY_KEY\n | typeof ITEMPROP_KEY;\ntype ExcludeRestMetaTagKeys<Key extends MetaTagKey> = {\n [K in Exclude<MetaTagKey, Key>]?: never;\n};\n\ntype MetaTagSelector =\n | typeof CHARSET_KEY\n | `${\n | typeof HTTP_EQUIV_SELECTOR_KEY\n | typeof NAME_KEY\n | typeof PROPERTY_KEY\n | typeof ITEMPROP_KEY}=\"${string}\"`;\ntype MetaTagMap = Record<MetaTagSelector, MetaTag>;\n\nexport function updateMetaTagsOnRouteChange(): void {\n const router = inject(Router);\n const metaService = inject(Meta);\n\n router.events\n .pipe(filter((event) => event instanceof NavigationEnd))\n .subscribe(() => {\n const metaTagMap = getMetaTagMap(router.routerState.snapshot.root);\n\n for (const metaTagSelector in metaTagMap) {\n const metaTag = metaTagMap[\n metaTagSelector as MetaTagSelector\n ] as NgMetaTag;\n metaService.updateTag(metaTag, metaTagSelector);\n }\n });\n}\n\nfunction getMetaTagMap(route: ActivatedRouteSnapshot): MetaTagMap {\n const metaTagMap = {} as MetaTagMap;\n let currentRoute: ActivatedRouteSnapshot | null = route;\n\n while (currentRoute) {\n const metaTags: MetaTag[] = currentRoute.data[ROUTE_META_TAGS_KEY] ?? [];\n for (const metaTag of metaTags) {\n metaTagMap[getMetaTagSelector(metaTag)] = metaTag;\n }\n\n currentRoute = currentRoute.firstChild;\n }\n\n return metaTagMap;\n}\n\nfunction getMetaTagSelector(metaTag: MetaTag): MetaTagSelector {\n if (metaTag.name) {\n return `${NAME_KEY}=\"${metaTag.name}\"`;\n }\n\n if (metaTag.property) {\n return `${PROPERTY_KEY}=\"${metaTag.property}\"`;\n }\n\n if (metaTag.httpEquiv) {\n return `${HTTP_EQUIV_SELECTOR_KEY}=\"${metaTag.httpEquiv}\"`;\n }\n\n if (metaTag.itemprop) {\n return `${ITEMPROP_KEY}=\"${metaTag.itemprop}\"`;\n }\n\n return CHARSET_KEY;\n}\n","export const ANALOG_META_KEY: unique symbol = Symbol(\n '@analogjs/router Analog Route Metadata Key',\n);\n\n/**\n * This variable reference is replaced with a glob of all route endpoints.\n */\nexport const ANALOG_PAGE_ENDPOINTS: any = {};\n","import type { ActivatedRouteSnapshot, Route } from '@angular/router';\nimport { injectBaseURL, injectAPIPrefix } from '@analogjs/router/tokens';\n\nimport { ANALOG_META_KEY } from './endpoints';\n\nexport function injectRouteEndpointURL(route: ActivatedRouteSnapshot): URL {\n const routeConfig = route.routeConfig as Route & {\n [ANALOG_META_KEY]: { endpoint: string; endpointKey: string };\n };\n\n const apiPrefix = injectAPIPrefix();\n const baseUrl = injectBaseURL();\n const { queryParams, fragment: hash, params, parent } = route;\n const segment = parent?.url.map((segment) => segment.path).join('/') || '';\n const url = new URL(\n '',\n import.meta.env['VITE_ANALOG_PUBLIC_BASE_URL'] ||\n baseUrl ||\n (typeof window !== 'undefined' && window.location.origin\n ? window.location.origin\n : ''),\n );\n url.pathname = `${\n url.pathname.endsWith('/') ? url.pathname : url.pathname + '/'\n }${apiPrefix}/_analog${routeConfig[ANALOG_META_KEY].endpoint}`;\n url.search = `${new URLSearchParams(queryParams).toString()}`;\n url.hash = hash ?? '';\n\n Object.keys(params).forEach((param) => {\n url.pathname = url.pathname.replace(`[${param}]`, params[param]);\n });\n url.pathname = url.pathname.replace('**', segment);\n\n return url;\n}\n","import { inject } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport type { Route } from '@angular/router';\nimport { firstValueFrom } from 'rxjs';\nimport { injectInternalServerFetch } from '@analogjs/router/tokens';\n\nimport {\n DefaultRouteMeta,\n RedirectRouteMeta,\n RouteConfig,\n RouteMeta,\n} from './models';\nimport { ROUTE_JSON_LD_KEY, isJsonLdObject } from './json-ld';\nimport { ROUTE_META_TAGS_KEY } from './meta-tags';\nimport { ANALOG_PAGE_ENDPOINTS, ANALOG_META_KEY } from './endpoints';\nimport { injectRouteEndpointURL } from './inject-route-endpoint-url';\n\nexport function toRouteConfig(routeMeta: RouteMeta | undefined): RouteConfig {\n if (routeMeta && isRedirectRouteMeta(routeMeta)) {\n return routeMeta;\n }\n\n const defaultMeta: DefaultRouteMeta = (routeMeta ?? {}) as DefaultRouteMeta;\n const { meta, jsonLd, ...routeConfig } = defaultMeta;\n\n if (Array.isArray(meta)) {\n routeConfig.data = { ...routeConfig.data, [ROUTE_META_TAGS_KEY]: meta };\n } else if (typeof meta === 'function') {\n routeConfig.resolve = {\n ...routeConfig.resolve,\n [ROUTE_META_TAGS_KEY]: meta,\n };\n }\n\n if (Array.isArray(jsonLd) || isJsonLdObject(jsonLd)) {\n routeConfig.data = { ...routeConfig.data, [ROUTE_JSON_LD_KEY]: jsonLd };\n } else if (typeof jsonLd === 'function') {\n routeConfig.resolve = {\n ...routeConfig.resolve,\n [ROUTE_JSON_LD_KEY]: jsonLd,\n };\n }\n\n routeConfig.runGuardsAndResolvers =\n routeConfig.runGuardsAndResolvers ?? 'paramsOrQueryParamsChange';\n routeConfig.resolve = {\n ...routeConfig.resolve,\n load: async (route) => {\n const routeConfig = route.routeConfig as Route & {\n [ANALOG_META_KEY]: { endpoint: string; endpointKey: string };\n };\n\n if (ANALOG_PAGE_ENDPOINTS[routeConfig[ANALOG_META_KEY].endpointKey]) {\n const http = inject(HttpClient);\n const url = injectRouteEndpointURL(route);\n const internalFetch = injectInternalServerFetch();\n\n if (internalFetch) {\n return internalFetch(url.pathname);\n }\n\n if (\n !!import.meta.env['VITE_ANALOG_PUBLIC_BASE_URL'] &&\n (globalThis as any).$fetch\n ) {\n return (globalThis as any).$fetch(url.pathname);\n }\n\n return firstValueFrom(http.get(`${url.href}`));\n }\n\n return {};\n },\n };\n\n return routeConfig;\n}\n\nfunction isRedirectRouteMeta(\n routeMeta: RouteMeta,\n): routeMeta is RedirectRouteMeta {\n return !!routeMeta.redirectTo;\n}\n","import { inject } from '@angular/core';\nimport { RouteExport } from './models';\n\ndeclare const Zone: any;\ntype RenderResult = string | { content: string };\ntype ContentRendererLike = {\n render: (content: string) => Promise<RenderResult>;\n};\n\n// The Zone is currently enabled by default, so we wouldn't need this check.\n// However, leaving this open space will be useful if zone.js becomes optional\n// in the future. This means we won't have to modify the current code, and it will\n// continue to work seamlessly.\nconst isNgZoneEnabled = typeof Zone !== 'undefined' && !!Zone.root;\n\nexport function toMarkdownModule(\n markdownFileFactory: () => Promise<string>,\n): () => Promise<RouteExport> {\n return async () => {\n const createLoader = () =>\n Promise.all([import('@analogjs/content'), markdownFileFactory()]);\n\n const [\n { parseRawContentFile, MarkdownRouteComponent, ContentRenderer },\n markdownFile,\n ]: [typeof import('@analogjs/content'), string] = await (isNgZoneEnabled\n ? // We are not able to use `runOutsideAngular` because we are not inside\n // an injection context to retrieve the `NgZone` instance.\n // The `Zone.root.run` is required when the code is running in the\n // browser since asynchronous tasks being scheduled in the current context\n // are a reason for unnecessary change detection cycles.\n Zone.root.run(createLoader)\n : createLoader());\n\n const { content, attributes } = parseRawContentFile(markdownFile);\n const { title, meta, jsonLd } = attributes;\n\n return {\n default: MarkdownRouteComponent,\n routeMeta: {\n data: { _analogContent: content },\n title,\n meta,\n jsonLd,\n resolve: {\n renderedAnalogContent: async () => {\n const contentRenderer = inject<any>(\n ContentRenderer as any,\n ) as ContentRendererLike;\n const rendered = await contentRenderer.render(content);\n return typeof rendered === 'string'\n ? rendered\n : (rendered as any).content;\n },\n },\n },\n };\n };\n}\n","export const ENDPOINT_EXTENSION = '.server.ts';\nexport const APP_DIR = 'src/app';\n","import { UrlSegment } from '@angular/router';\nimport type { Route } from '@angular/router';\nimport type { UrlMatcher } from '@angular/router';\n\nimport type { DefaultRouteMeta, RouteExport, RouteMeta } from './models';\nimport { toRouteConfig } from './route-config';\nimport { toMarkdownModule } from './markdown-helpers';\nimport { ENDPOINT_EXTENSION } from './constants';\nimport { ANALOG_META_KEY } from './endpoints';\n\n/**\n * This variable reference is replaced with a glob of all page routes.\n */\nexport const ANALOG_ROUTE_FILES = {};\n\n/**\n * This variable reference is replaced with a glob of all content routes.\n */\nexport const ANALOG_CONTENT_ROUTE_FILES = {};\n\nexport type Files = Record<string, () => Promise<RouteExport | string>>;\n\ntype RawRoute = {\n filename: string | null;\n rawSegment: string;\n ancestorRawSegments: string[];\n segment: string;\n level: number;\n children: RawRoute[];\n};\n\ntype RawRouteMap = Record<string, RawRoute>;\n\ntype RawRouteByLevelMap = Record<number, RawRouteMap>;\n\n/**\n * A function used to parse list of files and create configuration of routes.\n *\n * @param files\n * @returns Array of routes\n */\nexport function createRoutes(files: Files, debug = false): Route[] {\n const filenames = Object.keys(files);\n\n if (filenames.length === 0) {\n return [];\n }\n\n // map filenames to raw routes and group them by level\n const rawRoutesByLevelMap = filenames.reduce((acc, filename) => {\n const rawPath = toRawPath(filename);\n const rawSegments = rawPath.split('/');\n // nesting level starts at 0\n // rawPath: /products => level: 0\n // rawPath: /products/:id => level: 1\n const level = rawSegments.length - 1;\n const rawSegment = rawSegments[level];\n const ancestorRawSegments = rawSegments.slice(0, level);\n\n return {\n ...acc,\n [level]: {\n ...acc[level],\n [rawPath]: {\n filename,\n rawSegment,\n ancestorRawSegments,\n segment: toSegment(rawSegment),\n level,\n children: [],\n },\n },\n };\n }, {} as RawRouteByLevelMap);\n\n const allLevels = Object.keys(rawRoutesByLevelMap).map(Number);\n const maxLevel = Math.max(...allLevels);\n\n // add each raw route to its parent's children array\n for (let level = maxLevel; level > 0; level--) {\n const rawRoutesMap = rawRoutesByLevelMap[level];\n const rawPaths = Object.keys(rawRoutesMap);\n\n for (const rawPath of rawPaths) {\n const rawRoute = rawRoutesMap[rawPath];\n const parentRawPath = rawRoute.ancestorRawSegments.join('/');\n const parentRawSegmentIndex = rawRoute.ancestorRawSegments.length - 1;\n const parentRawSegment =\n rawRoute.ancestorRawSegments[parentRawSegmentIndex];\n\n // create the parent level and/or raw route if it does not exist\n // parent route won't exist for nested routes that don't have a layout route\n rawRoutesByLevelMap[level - 1] ||= {};\n rawRoutesByLevelMap[level - 1][parentRawPath] ||= {\n filename: null,\n rawSegment: parentRawSegment,\n ancestorRawSegments: rawRoute.ancestorRawSegments.slice(\n 0,\n parentRawSegmentIndex,\n ),\n segment: toSegment(parentRawSegment),\n level: level - 1,\n children: [],\n };\n\n rawRoutesByLevelMap[level - 1][parentRawPath].children.push(rawRoute);\n }\n }\n\n // only take raw routes from the root level\n // since they already contain nested routes as their children\n const rootRawRoutesMap = rawRoutesByLevelMap[0];\n const rawRoutes = Object.keys(rootRawRoutesMap).map(\n (segment) => rootRawRoutesMap[segment],\n );\n sortRawRoutes(rawRoutes);\n\n return toRoutes(rawRoutes, files, debug);\n}\n\nfunction toRawPath(filename: string): string {\n return (\n filename\n .replace(\n // convert to relative path and remove file extension\n /^(?:[a-zA-Z]:[\\\\/])?(.*?)[\\\\/](?:routes|pages)[\\\\/]|(?:[\\\\/](?:app[\\\\/](?:routes|pages)|src[\\\\/]content)[\\\\/])|(\\.page\\.(js|ts|analog|ag)$)|(\\.(ts|md|analog|ag)$)/g,\n '',\n )\n // [[...slug]] => placeholder (named empty) which is stripped by toSegment\n .replace(/\\[\\[\\.\\.\\.([^\\]]+)\\]\\]/g, '(opt-$1)')\n .replace(/\\[\\.{3}.+\\]/, '**') // [...not-found] => **\n .replace(/\\[([^\\]]+)\\]/g, ':$1')\n ); // [id] => :id\n}\n\nfunction toSegment(rawSegment: string): string {\n return rawSegment\n .replace(/index|\\(.*?\\)/g, '') // replace named empty segments\n .replace(/\\.|\\/+/g, '/') // replace dots with slashes and remove redundant slashes\n .replace(/^\\/+|\\/+$/g, ''); // remove trailing slashes\n}\n\nfunction createOptionalCatchAllMatcher(paramName: string): UrlMatcher {\n return (segments) => {\n if (segments.length === 0) {\n return null;\n }\n const joined = segments.map((s) => s.path).join('/');\n return {\n consumed: segments,\n posParams: { [paramName]: new UrlSegment(joined, {}) },\n };\n };\n}\n\nfunction toRoutes(rawRoutes: RawRoute[], files: Files, debug = false): Route[] {\n const routes: Route[] = [];\n\n for (const rawRoute of rawRoutes) {\n const children: Route[] | undefined =\n rawRoute.children.length > 0\n ? toRoutes(rawRoute.children, files, debug)\n : undefined;\n let module: (() => Promise<RouteExport>) | undefined = undefined;\n let analogMeta: { endpoint: string; endpointKey: string } | undefined =\n undefined;\n\n if (rawRoute.filename) {\n const isMarkdownFile = rawRoute.filename.endsWith('.md');\n\n if (!debug) {\n module = isMarkdownFile\n ? toMarkdownModule(files[rawRoute.filename] as () => Promise<string>)\n : (files[rawRoute.filename] as () => Promise<RouteExport>);\n }\n\n const endpointKey = rawRoute.filename.replace(\n /\\.page\\.(ts|analog|ag)$/,\n ENDPOINT_EXTENSION,\n );\n\n // get endpoint path\n const rawEndpoint = rawRoute.filename\n .replace(/\\.page\\.(ts|analog|ag)$/, '')\n .replace(/\\[\\[\\.\\.\\..+\\]\\]/, '**')\n .replace(/\\[\\.{3}.+\\]/, '**') // [...not-found] => **\n .replace(/^(.*?)\\/pages/, '/pages');\n\n // replace periods, remove (index) paths\n const endpoint = (rawEndpoint || '')\n .replace(/\\./g, '/')\n .replace(/\\/\\((.*?)\\)$/, '/-$1-');\n\n analogMeta = {\n endpoint,\n endpointKey,\n };\n }\n\n // Detect Next.js-style optional catch-all at this node: [[...param]]\n const optCatchAllMatch = rawRoute.filename?.match(/\\[\\[\\.\\.\\.([^\\]]+)\\]\\]/);\n const optCatchAllParam = optCatchAllMatch ? optCatchAllMatch[1] : null;\n\n type DebugRoute = Route & {\n filename?: string | null | undefined;\n isLayout?: boolean;\n };\n\n const route: Route & { meta?: typeof analogMeta } & DebugRoute = module\n ? {\n path: rawRoute.segment,\n loadChildren: () =>\n module!().then((m) => {\n if (import.meta.env.DEV) {\n const hasModuleDefault = !!m.default;\n const hasRedirect = !!m.routeMeta?.redirectTo;\n\n if (!hasModuleDefault && !hasRedirect) {\n console.warn(\n `[Analog] Missing default export at ${rawRoute.filename}`,\n );\n }\n }\n\n const routeMeta = mergeRouteJsonLdIntoRouteMeta(\n m.routeMeta as RouteMeta | undefined,\n m.routeJsonLd,\n );\n\n const routeConfig = toRouteConfig(routeMeta);\n const hasRedirect = 'redirectTo' in routeConfig;\n const baseChild = hasRedirect\n ? {\n path: '',\n ...routeConfig,\n }\n : {\n path: '',\n component: m.default,\n ...routeConfig,\n children,\n [ANALOG_META_KEY]: analogMeta,\n };\n\n // Base route first so static matches win, then optional catch-all matcher\n return [\n {\n ...baseChild,\n },\n ...(optCatchAllParam\n ? [\n {\n matcher:\n createOptionalCatchAllMatcher(optCatchAllParam),\n ...(hasRedirect\n ? routeConfig\n : {\n component: m.default,\n ...routeConfig,\n [ANALOG_META_KEY]: analogMeta,\n }),\n },\n ]\n : []),\n ];\n }),\n }\n : {\n path: rawRoute.segment,\n ...(debug\n ? {\n filename: rawRoute.filename ? rawRoute.filename : undefined,\n isLayout: children && children.length > 0 ? true : false,\n }\n : {}),\n children,\n };\n\n routes.push(route);\n }\n\n return routes;\n}\n\nfunction mergeRouteJsonLdIntoRouteMeta(\n routeMeta: RouteMeta | undefined,\n routeJsonLd: RouteExport['routeJsonLd'],\n): RouteMeta | undefined {\n if (!routeJsonLd) {\n return routeMeta;\n }\n\n if (!routeMeta) {\n return { jsonLd: routeJsonLd };\n }\n\n if (isRedirectRouteMeta(routeMeta) || routeMeta.jsonLd) {\n return routeMeta;\n }\n\n return {\n ...routeMeta,\n jsonLd: routeJsonLd,\n };\n}\n\nfunction isRedirectRouteMeta(\n routeMeta: RouteMeta,\n): routeMeta is Exclude<RouteMeta, DefaultRouteMeta> {\n return 'redirectTo' in routeMeta && !!routeMeta.redirectTo;\n}\n\nfunction sortRawRoutes(rawRoutes: RawRoute[]): void {\n rawRoutes.sort((a, b) => {\n let segmentA = deprioritizeSegment(a.segment);\n let segmentB = deprioritizeSegment(b.segment);\n\n // prioritize routes with fewer children\n if (a.children.length > b.children.length) {\n segmentA = `~${segmentA}`;\n } else if (a.children.length < b.children.length) {\n segmentB = `~${segmentB}`;\n }\n\n return segmentA > segmentB ? 1 : -1;\n });\n\n for (const rawRoute of rawRoutes) {\n sortRawRoutes(rawRoute.children);\n }\n}\n\nfunction deprioritizeSegment(segment: string): string {\n // deprioritize param and wildcard segments\n return segment.replace(':', '~~').replace('**', '~~~~');\n}\n\nexport const routes: Route[] = createRoutes({\n ...ANALOG_ROUTE_FILES,\n ...ANALOG_CONTENT_ROUTE_FILES,\n});\n","import { inject, InjectionToken } from '@angular/core';\nimport { Route } from '@angular/router';\n\nimport {\n ANALOG_CONTENT_ROUTE_FILES,\n ANALOG_ROUTE_FILES,\n createRoutes,\n} from '../routes';\n\nexport const DEBUG_ROUTES: InjectionToken<(Route & DebugRoute)[]> =\n new InjectionToken<(Route & DebugRoute)[]>('@analogjs/router debug routes', {\n providedIn: 'root',\n factory() {\n const debugRoutes = createRoutes(\n {\n ...ANALOG_ROUTE_FILES,\n ...ANALOG_CONTENT_ROUTE_FILES,\n },\n true,\n );\n\n return debugRoutes as (Route & DebugRoute)[];\n },\n });\n\nexport type DebugRoute = {\n path: string;\n filename: string;\n isLayout: boolean;\n children?: DebugRoute[];\n};\n\nexport function injectDebugRoutes(): (Route & DebugRoute)[] {\n return inject(DEBUG_ROUTES);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"routes.mjs","names":[],"sources":["../../src/lib/json-ld.ts","../../src/lib/meta-tags.ts","../../src/lib/endpoints.ts","../../src/lib/inject-route-endpoint-url.ts","../../src/lib/route-config.ts","../../src/lib/markdown-helpers.ts","../../src/lib/constants.ts","../../src/lib/routes.ts","../../src/lib/debug/routes.ts"],"sourcesContent":["import { DOCUMENT } from '@angular/common';\nimport { inject } from '@angular/core';\nimport { ActivatedRouteSnapshot, NavigationEnd, Router } from '@angular/router';\nimport { filter } from 'rxjs/operators';\n\nimport type { Graph, Thing, WithContext } from 'schema-dts';\n\nexport type JsonLdObject = Record<string, unknown>;\n\nexport function isJsonLdObject(value: unknown): value is JsonLdObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function normalizeJsonLd(value: unknown): JsonLdObject[] {\n if (Array.isArray(value)) {\n return value.filter(isJsonLdObject);\n }\n\n return isJsonLdObject(value) ? [value] : [];\n}\n\nexport type JsonLd = JsonLdObject | JsonLdObject[];\n\n/**\n * Typed JSON-LD document based on `schema-dts`.\n *\n * Accepts single Schema.org nodes (`WithContext<Thing>`),\n * `@graph`-based documents (`Graph`), or arrays of nodes.\n *\n * This is the canonical JSON-LD type for route authoring surfaces\n * (`routeMeta.jsonLd`, `routeJsonLd`, generated manifest).\n *\n * @example\n * ```ts\n * import type { WebPage, WithContext } from 'schema-dts';\n *\n * export const routeMeta = {\n * jsonLd: {\n * '@context': 'https://schema.org',\n * '@type': 'WebPage',\n * name: 'Products',\n * } satisfies WithContext<WebPage>,\n * };\n * ```\n */\nexport type AnalogJsonLdDocument =\n | WithContext<Thing>\n | Graph\n | Array<WithContext<Thing>>;\n\nexport const ROUTE_JSON_LD_KEY: unique symbol = Symbol(\n '@analogjs/router Route JSON-LD Key',\n);\nconst JSON_LD_SCRIPT_SELECTOR = 'script[data-analog-json-ld]';\n\nexport function updateJsonLdOnRouteChange(): void {\n const router = inject(Router);\n const document = inject(DOCUMENT);\n\n router.events\n .pipe(filter((event) => event instanceof NavigationEnd))\n .subscribe(() => {\n applyJsonLdToDocument(\n document,\n getJsonLdEntries(router.routerState.snapshot.root),\n );\n });\n}\n\nexport function serializeJsonLd(entry: JsonLdObject): string | null {\n try {\n return JSON.stringify(entry)\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e')\n .replace(/&/g, '\\\\u0026')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n } catch {\n return null;\n }\n}\n\nfunction getJsonLdEntries(route: ActivatedRouteSnapshot): JsonLdObject[] {\n const entries: JsonLdObject[] = [];\n let currentRoute: ActivatedRouteSnapshot | null = route;\n\n while (currentRoute) {\n entries.push(...normalizeJsonLd(currentRoute.data[ROUTE_JSON_LD_KEY]));\n currentRoute = currentRoute.firstChild;\n }\n\n return entries;\n}\n\nfunction applyJsonLdToDocument(\n document: Document,\n entries: JsonLdObject[],\n): void {\n document.querySelectorAll(JSON_LD_SCRIPT_SELECTOR).forEach((element) => {\n element.remove();\n });\n\n if (entries.length === 0) {\n return;\n }\n\n const head = document.head || document.getElementsByTagName('head')[0];\n if (!head) {\n return;\n }\n\n entries.forEach((entry, index) => {\n const serialized = serializeJsonLd(entry);\n if (!serialized) {\n return;\n }\n\n const script = document.createElement('script');\n script.type = 'application/ld+json';\n script.setAttribute('data-analog-json-ld', 'true');\n script.setAttribute('data-analog-json-ld-index', String(index));\n script.textContent = serialized;\n head.appendChild(script);\n });\n}\n","import { inject } from '@angular/core';\nimport { Meta, MetaDefinition as NgMetaTag } from '@angular/platform-browser';\nimport { ActivatedRouteSnapshot, NavigationEnd, Router } from '@angular/router';\nimport { filter } from 'rxjs/operators';\n\nexport const ROUTE_META_TAGS_KEY: unique symbol = Symbol(\n '@analogjs/router Route Meta Tags Key',\n);\n\nconst CHARSET_KEY = 'charset';\nconst HTTP_EQUIV_KEY = 'httpEquiv';\n// httpEquiv selector key needs to be in kebab case format\nconst HTTP_EQUIV_SELECTOR_KEY = 'http-equiv';\nconst NAME_KEY = 'name';\nconst PROPERTY_KEY = 'property';\nconst CONTENT_KEY = 'content';\nconst ITEMPROP_KEY = 'itemprop';\n\nexport type MetaTag =\n | (CharsetMetaTag & ExcludeRestMetaTagKeys<typeof CHARSET_KEY>)\n | (HttpEquivMetaTag & ExcludeRestMetaTagKeys<typeof HTTP_EQUIV_KEY>)\n | (NameMetaTag & ExcludeRestMetaTagKeys<typeof NAME_KEY>)\n | (PropertyMetaTag & ExcludeRestMetaTagKeys<typeof PROPERTY_KEY>)\n | (ItempropMetaTag & ExcludeRestMetaTagKeys<typeof ITEMPROP_KEY>);\n\ntype CharsetMetaTag = { [CHARSET_KEY]: string };\ntype HttpEquivMetaTag = { [HTTP_EQUIV_KEY]: string; [CONTENT_KEY]: string };\ntype NameMetaTag = { [NAME_KEY]: string; [CONTENT_KEY]: string };\ntype PropertyMetaTag = { [PROPERTY_KEY]: string; [CONTENT_KEY]: string };\ntype ItempropMetaTag = { [ITEMPROP_KEY]: string; [CONTENT_KEY]: string };\n\ntype MetaTagKey =\n | typeof CHARSET_KEY\n | typeof HTTP_EQUIV_KEY\n | typeof NAME_KEY\n | typeof PROPERTY_KEY\n | typeof ITEMPROP_KEY;\ntype ExcludeRestMetaTagKeys<Key extends MetaTagKey> = {\n [K in Exclude<MetaTagKey, Key>]?: never;\n};\n\ntype MetaTagSelector =\n | typeof CHARSET_KEY\n | `${\n | typeof HTTP_EQUIV_SELECTOR_KEY\n | typeof NAME_KEY\n | typeof PROPERTY_KEY\n | typeof ITEMPROP_KEY}=\"${string}\"`;\ntype MetaTagMap = Record<MetaTagSelector, MetaTag>;\n\nexport function updateMetaTagsOnRouteChange(): void {\n const router = inject(Router);\n const metaService = inject(Meta);\n\n router.events\n .pipe(filter((event) => event instanceof NavigationEnd))\n .subscribe(() => {\n const metaTagMap = getMetaTagMap(router.routerState.snapshot.root);\n\n for (const metaTagSelector in metaTagMap) {\n const metaTag = metaTagMap[\n metaTagSelector as MetaTagSelector\n ] as NgMetaTag;\n metaService.updateTag(metaTag, metaTagSelector);\n }\n });\n}\n\nfunction getMetaTagMap(route: ActivatedRouteSnapshot): MetaTagMap {\n const metaTagMap = {} as MetaTagMap;\n let currentRoute: ActivatedRouteSnapshot | null = route;\n\n while (currentRoute) {\n const metaTags: MetaTag[] = currentRoute.data[ROUTE_META_TAGS_KEY] ?? [];\n for (const metaTag of metaTags) {\n metaTagMap[getMetaTagSelector(metaTag)] = metaTag;\n }\n\n currentRoute = currentRoute.firstChild;\n }\n\n return metaTagMap;\n}\n\nfunction getMetaTagSelector(metaTag: MetaTag): MetaTagSelector {\n if (metaTag.name) {\n return `${NAME_KEY}=\"${metaTag.name}\"`;\n }\n\n if (metaTag.property) {\n return `${PROPERTY_KEY}=\"${metaTag.property}\"`;\n }\n\n if (metaTag.httpEquiv) {\n return `${HTTP_EQUIV_SELECTOR_KEY}=\"${metaTag.httpEquiv}\"`;\n }\n\n if (metaTag.itemprop) {\n return `${ITEMPROP_KEY}=\"${metaTag.itemprop}\"`;\n }\n\n return CHARSET_KEY;\n}\n","export const ANALOG_META_KEY: unique symbol = Symbol(\n '@analogjs/router Analog Route Metadata Key',\n);\n\n/**\n * This variable reference is replaced with a glob of all route endpoints.\n */\nexport const ANALOG_PAGE_ENDPOINTS: any = {};\n","import type { ActivatedRouteSnapshot, Route } from '@angular/router';\nimport { injectBaseURL, injectAPIPrefix } from '@analogjs/router/tokens';\n\nimport { ANALOG_META_KEY } from './endpoints';\n\nexport function injectRouteEndpointURL(route: ActivatedRouteSnapshot): URL {\n const routeConfig = route.routeConfig as Route & {\n [ANALOG_META_KEY]: { endpoint: string; endpointKey: string };\n };\n\n const apiPrefix = injectAPIPrefix();\n const baseUrl = injectBaseURL();\n const { queryParams, fragment: hash, params, parent } = route;\n const segment = parent?.url.map((segment) => segment.path).join('/') || '';\n const url = new URL(\n '',\n import.meta.env['VITE_ANALOG_PUBLIC_BASE_URL'] ||\n baseUrl ||\n (typeof window !== 'undefined' && window.location.origin\n ? window.location.origin\n : ''),\n );\n url.pathname = `${\n url.pathname.endsWith('/') ? url.pathname : url.pathname + '/'\n }${apiPrefix}/_analog${routeConfig[ANALOG_META_KEY].endpoint}`;\n url.search = `${new URLSearchParams(queryParams).toString()}`;\n url.hash = hash ?? '';\n\n Object.keys(params).forEach((param) => {\n url.pathname = url.pathname.replace(`[${param}]`, params[param]);\n });\n url.pathname = url.pathname.replace('**', segment);\n\n return url;\n}\n","import { inject } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport type { Route } from '@angular/router';\nimport { firstValueFrom } from 'rxjs';\nimport { injectInternalServerFetch } from '@analogjs/router/tokens';\n\nimport {\n DefaultRouteMeta,\n RedirectRouteMeta,\n RouteConfig,\n RouteMeta,\n} from './models';\nimport { ROUTE_JSON_LD_KEY, isJsonLdObject } from './json-ld';\nimport { ROUTE_META_TAGS_KEY } from './meta-tags';\nimport { ANALOG_PAGE_ENDPOINTS, ANALOG_META_KEY } from './endpoints';\nimport { injectRouteEndpointURL } from './inject-route-endpoint-url';\n\nexport function toRouteConfig(routeMeta: RouteMeta | undefined): RouteConfig {\n if (routeMeta && isRedirectRouteMeta(routeMeta)) {\n return routeMeta;\n }\n\n const defaultMeta: DefaultRouteMeta = (routeMeta ?? {}) as DefaultRouteMeta;\n const { meta, jsonLd, ...routeConfig } = defaultMeta;\n\n if (Array.isArray(meta)) {\n routeConfig.data = { ...routeConfig.data, [ROUTE_META_TAGS_KEY]: meta };\n } else if (typeof meta === 'function') {\n routeConfig.resolve = {\n ...routeConfig.resolve,\n [ROUTE_META_TAGS_KEY]: meta,\n };\n }\n\n if (Array.isArray(jsonLd) || isJsonLdObject(jsonLd)) {\n routeConfig.data = { ...routeConfig.data, [ROUTE_JSON_LD_KEY]: jsonLd };\n } else if (typeof jsonLd === 'function') {\n routeConfig.resolve = {\n ...routeConfig.resolve,\n [ROUTE_JSON_LD_KEY]: jsonLd,\n };\n }\n\n routeConfig.runGuardsAndResolvers =\n routeConfig.runGuardsAndResolvers ?? 'paramsOrQueryParamsChange';\n routeConfig.resolve = {\n ...routeConfig.resolve,\n load: async (route) => {\n const routeConfig = route.routeConfig as Route & {\n [ANALOG_META_KEY]: { endpoint: string; endpointKey: string };\n };\n\n if (ANALOG_PAGE_ENDPOINTS[routeConfig[ANALOG_META_KEY].endpointKey]) {\n const http = inject(HttpClient);\n const url = injectRouteEndpointURL(route);\n const internalFetch = injectInternalServerFetch();\n\n if (internalFetch) {\n return internalFetch(url.pathname);\n }\n\n if (\n !!import.meta.env['VITE_ANALOG_PUBLIC_BASE_URL'] &&\n (globalThis as any).$fetch\n ) {\n return (globalThis as any).$fetch(url.pathname);\n }\n\n return firstValueFrom(http.get(`${url.href}`));\n }\n\n return {};\n },\n };\n\n return routeConfig;\n}\n\nfunction isRedirectRouteMeta(\n routeMeta: RouteMeta,\n): routeMeta is RedirectRouteMeta {\n return !!routeMeta.redirectTo;\n}\n","import { inject } from '@angular/core';\nimport { RouteExport } from './models';\n\ndeclare const Zone: any;\ntype RenderResult = string | { content: string };\ntype ContentRendererLike = {\n render: (content: string) => Promise<RenderResult>;\n};\n\n// The Zone is currently enabled by default, so we wouldn't need this check.\n// However, leaving this open space will be useful if zone.js becomes optional\n// in the future. This means we won't have to modify the current code, and it will\n// continue to work seamlessly.\nconst isNgZoneEnabled = typeof Zone !== 'undefined' && !!Zone.root;\n\nexport function toMarkdownModule(\n markdownFileFactory: () => Promise<string>,\n): () => Promise<RouteExport> {\n return async () => {\n const createLoader = () =>\n Promise.all([import('@analogjs/content'), markdownFileFactory()]);\n\n const [\n { parseRawContentFile, MarkdownRouteComponent, ContentRenderer },\n markdownFile,\n ]: [typeof import('@analogjs/content'), string] = await (isNgZoneEnabled\n ? // We are not able to use `runOutsideAngular` because we are not inside\n // an injection context to retrieve the `NgZone` instance.\n // The `Zone.root.run` is required when the code is running in the\n // browser since asynchronous tasks being scheduled in the current context\n // are a reason for unnecessary change detection cycles.\n Zone.root.run(createLoader)\n : createLoader());\n\n const { content, attributes } = parseRawContentFile(markdownFile);\n const { title, meta, jsonLd } = attributes;\n\n return {\n default: MarkdownRouteComponent,\n routeMeta: {\n data: { _analogContent: content },\n title,\n meta,\n jsonLd,\n resolve: {\n renderedAnalogContent: async () => {\n const contentRenderer = inject<any>(\n ContentRenderer as any,\n ) as ContentRendererLike;\n const rendered = await contentRenderer.render(content);\n return typeof rendered === 'string'\n ? rendered\n : (rendered as any).content;\n },\n },\n },\n };\n };\n}\n","export const ENDPOINT_EXTENSION = '.server.ts';\nexport const APP_DIR = 'src/app';\n","import { UrlSegment } from '@angular/router';\nimport type { Route } from '@angular/router';\nimport type { UrlMatcher } from '@angular/router';\n\nimport type { DefaultRouteMeta, RouteExport, RouteMeta } from './models';\nimport { toRouteConfig } from './route-config';\nimport { toMarkdownModule } from './markdown-helpers';\nimport { ENDPOINT_EXTENSION } from './constants';\nimport { ANALOG_META_KEY } from './endpoints';\n\n/**\n * This variable reference is replaced with a glob of all page routes.\n */\nexport const ANALOG_ROUTE_FILES = {};\n\n/**\n * This variable reference is replaced with a glob of all content routes.\n */\nexport const ANALOG_CONTENT_ROUTE_FILES = {};\n\nexport type Files = Record<string, () => Promise<RouteExport | string>>;\n\ntype RawRoute = {\n filename: string | null;\n rawSegment: string;\n ancestorRawSegments: string[];\n segment: string;\n level: number;\n children: RawRoute[];\n};\n\ntype RawRouteMap = Record<string, RawRoute>;\n\ntype RawRouteByLevelMap = Record<number, RawRouteMap>;\n\n/**\n * A function used to parse list of files and create configuration of routes.\n *\n * @param files\n * @returns Array of routes\n */\nexport function createRoutes(files: Files, debug = false): Route[] {\n const filenames = Object.keys(files);\n\n if (filenames.length === 0) {\n return [];\n }\n\n // map filenames to raw routes and group them by level\n const rawRoutesByLevelMap = filenames.reduce((acc, filename) => {\n const rawPath = toRawPath(filename);\n const rawSegments = rawPath.split('/');\n // nesting level starts at 0\n // rawPath: /products => level: 0\n // rawPath: /products/:id => level: 1\n const level = rawSegments.length - 1;\n const rawSegment = rawSegments[level];\n const ancestorRawSegments = rawSegments.slice(0, level);\n\n return {\n ...acc,\n [level]: {\n ...acc[level],\n [rawPath]: {\n filename,\n rawSegment,\n ancestorRawSegments,\n segment: toSegment(rawSegment),\n level,\n children: [],\n },\n },\n };\n }, {} as RawRouteByLevelMap);\n\n const allLevels = Object.keys(rawRoutesByLevelMap).map(Number);\n const maxLevel = Math.max(...allLevels);\n\n // add each raw route to its parent's children array\n for (let level = maxLevel; level > 0; level--) {\n const rawRoutesMap = rawRoutesByLevelMap[level];\n const rawPaths = Object.keys(rawRoutesMap);\n\n for (const rawPath of rawPaths) {\n const rawRoute = rawRoutesMap[rawPath];\n const parentRawPath = rawRoute.ancestorRawSegments.join('/');\n const parentRawSegmentIndex = rawRoute.ancestorRawSegments.length - 1;\n const parentRawSegment =\n rawRoute.ancestorRawSegments[parentRawSegmentIndex];\n\n // create the parent level and/or raw route if it does not exist\n // parent route won't exist for nested routes that don't have a layout route\n rawRoutesByLevelMap[level - 1] ||= {};\n rawRoutesByLevelMap[level - 1][parentRawPath] ||= {\n filename: null,\n rawSegment: parentRawSegment,\n ancestorRawSegments: rawRoute.ancestorRawSegments.slice(\n 0,\n parentRawSegmentIndex,\n ),\n segment: toSegment(parentRawSegment),\n level: level - 1,\n children: [],\n };\n\n rawRoutesByLevelMap[level - 1][parentRawPath].children.push(rawRoute);\n }\n }\n\n // only take raw routes from the root level\n // since they already contain nested routes as their children\n const rootRawRoutesMap = rawRoutesByLevelMap[0];\n const rawRoutes = Object.keys(rootRawRoutesMap).map(\n (segment) => rootRawRoutesMap[segment],\n );\n sortRawRoutes(rawRoutes);\n\n return toRoutes(rawRoutes, files, debug);\n}\n\nfunction toRawPath(filename: string): string {\n return (\n filename\n .replace(\n // convert to relative path and remove file extension\n /^(?:[a-zA-Z]:[\\\\/])?(.*?)[\\\\/](?:routes|pages)[\\\\/]|(?:[\\\\/](?:app[\\\\/](?:routes|pages)|src[\\\\/]content)[\\\\/])|(\\.page\\.(js|ts|analog|ag)$)|(\\.(ts|md|analog|ag)$)/g,\n '',\n )\n // [[...slug]] => placeholder (named empty) which is stripped by toSegment\n .replace(/\\[\\[\\.\\.\\.([^\\]]+)\\]\\]/g, '(opt-$1)')\n .replace(/\\[\\.{3}.+\\]/, '**') // [...not-found] => **\n .replace(/\\[([^\\]]+)\\]/g, ':$1')\n ); // [id] => :id\n}\n\nfunction toSegment(rawSegment: string): string {\n return rawSegment\n .replace(/index|\\(.*?\\)/g, '') // replace named empty segments\n .replace(/\\.|\\/+/g, '/') // replace dots with slashes and remove redundant slashes\n .replace(/^\\/+|\\/+$/g, ''); // remove trailing slashes\n}\n\nfunction createOptionalCatchAllMatcher(paramName: string): UrlMatcher {\n return (segments) => {\n if (segments.length === 0) {\n return null;\n }\n const joined = segments.map((s) => s.path).join('/');\n return {\n consumed: segments,\n posParams: { [paramName]: new UrlSegment(joined, {}) },\n };\n };\n}\n\nfunction toRoutes(rawRoutes: RawRoute[], files: Files, debug = false): Route[] {\n const routes: Route[] = [];\n\n for (const rawRoute of rawRoutes) {\n const children: Route[] | undefined =\n rawRoute.children.length > 0\n ? toRoutes(rawRoute.children, files, debug)\n : undefined;\n let module: (() => Promise<RouteExport>) | undefined = undefined;\n let analogMeta: { endpoint: string; endpointKey: string } | undefined =\n undefined;\n\n if (rawRoute.filename) {\n const isMarkdownFile = rawRoute.filename.endsWith('.md');\n\n if (!debug) {\n module = isMarkdownFile\n ? toMarkdownModule(files[rawRoute.filename] as () => Promise<string>)\n : (files[rawRoute.filename] as () => Promise<RouteExport>);\n }\n\n const endpointKey = rawRoute.filename.replace(\n /\\.page\\.(ts|analog|ag)$/,\n ENDPOINT_EXTENSION,\n );\n\n // get endpoint path\n const rawEndpoint = rawRoute.filename\n .replace(/\\.page\\.(ts|analog|ag)$/, '')\n .replace(/\\[\\[\\.\\.\\..+\\]\\]/, '**')\n .replace(/\\[\\.{3}.+\\]/, '**') // [...not-found] => **\n .replace(/^(.*?)\\/pages/, '/pages');\n\n // replace periods, remove (index) paths\n const endpoint = (rawEndpoint || '')\n .replace(/\\./g, '/')\n .replace(/\\/\\((.*?)\\)$/, '/-$1-');\n\n analogMeta = {\n endpoint,\n endpointKey,\n };\n }\n\n // Detect Next.js-style optional catch-all at this node: [[...param]]\n const optCatchAllMatch = rawRoute.filename?.match(/\\[\\[\\.\\.\\.([^\\]]+)\\]\\]/);\n const optCatchAllParam = optCatchAllMatch ? optCatchAllMatch[1] : null;\n\n type DebugRoute = Route & {\n filename?: string | null | undefined;\n isLayout?: boolean;\n };\n\n const route: Route & { meta?: typeof analogMeta } & DebugRoute = module\n ? {\n path: rawRoute.segment,\n loadChildren: () =>\n module!().then((m) => {\n if (import.meta.env.DEV) {\n const hasModuleDefault = !!m.default;\n const hasRedirect = !!m.routeMeta?.redirectTo;\n\n if (!hasModuleDefault && !hasRedirect) {\n console.warn(\n `[Analog] Missing default export at ${rawRoute.filename}`,\n );\n }\n }\n\n const routeMeta = mergeRouteJsonLdIntoRouteMeta(\n m.routeMeta as RouteMeta | undefined,\n m.routeJsonLd,\n );\n\n const routeConfig = toRouteConfig(routeMeta);\n const hasRedirect = 'redirectTo' in routeConfig;\n const baseChild = hasRedirect\n ? {\n path: '',\n ...routeConfig,\n }\n : {\n path: '',\n component: m.default,\n ...routeConfig,\n children,\n [ANALOG_META_KEY]: analogMeta,\n };\n\n // Base route first so static matches win, then optional catch-all matcher\n return [\n {\n ...baseChild,\n },\n ...(optCatchAllParam\n ? [\n {\n matcher:\n createOptionalCatchAllMatcher(optCatchAllParam),\n ...(hasRedirect\n ? routeConfig\n : {\n component: m.default,\n ...routeConfig,\n [ANALOG_META_KEY]: analogMeta,\n }),\n },\n ]\n : []),\n ];\n }),\n }\n : {\n path: rawRoute.segment,\n ...(debug\n ? {\n filename: rawRoute.filename ? rawRoute.filename : undefined,\n isLayout: children && children.length > 0 ? true : false,\n }\n : {}),\n children,\n };\n\n routes.push(route);\n }\n\n return routes;\n}\n\nfunction mergeRouteJsonLdIntoRouteMeta(\n routeMeta: RouteMeta | undefined,\n routeJsonLd: RouteExport['routeJsonLd'],\n): RouteMeta | undefined {\n if (!routeJsonLd) {\n return routeMeta;\n }\n\n if (!routeMeta) {\n return { jsonLd: routeJsonLd };\n }\n\n if (isRedirectRouteMeta(routeMeta) || routeMeta.jsonLd) {\n return routeMeta;\n }\n\n return {\n ...routeMeta,\n jsonLd: routeJsonLd,\n };\n}\n\nfunction isRedirectRouteMeta(\n routeMeta: RouteMeta,\n): routeMeta is Exclude<RouteMeta, DefaultRouteMeta> {\n return 'redirectTo' in routeMeta && !!routeMeta.redirectTo;\n}\n\nfunction sortRawRoutes(rawRoutes: RawRoute[]): void {\n rawRoutes.sort((a, b) => {\n let segmentA = deprioritizeSegment(a.segment);\n let segmentB = deprioritizeSegment(b.segment);\n\n // prioritize routes with fewer children\n if (a.children.length > b.children.length) {\n segmentA = `~${segmentA}`;\n } else if (a.children.length < b.children.length) {\n segmentB = `~${segmentB}`;\n }\n\n return segmentA > segmentB ? 1 : -1;\n });\n\n for (const rawRoute of rawRoutes) {\n sortRawRoutes(rawRoute.children);\n }\n}\n\nfunction deprioritizeSegment(segment: string): string {\n // deprioritize param and wildcard segments\n return segment.replace(':', '~~').replace('**', '~~~~');\n}\n\nexport const routes: Route[] = createRoutes({\n ...ANALOG_ROUTE_FILES,\n ...ANALOG_CONTENT_ROUTE_FILES,\n});\n","import { inject, InjectionToken } from '@angular/core';\nimport { Route } from '@angular/router';\n\nimport {\n ANALOG_CONTENT_ROUTE_FILES,\n ANALOG_ROUTE_FILES,\n createRoutes,\n} from '../routes';\n\nexport const DEBUG_ROUTES: InjectionToken<(Route & DebugRoute)[]> =\n new InjectionToken<(Route & DebugRoute)[]>('@analogjs/router debug routes', {\n providedIn: 'root',\n factory() {\n const debugRoutes = createRoutes(\n {\n ...ANALOG_ROUTE_FILES,\n ...ANALOG_CONTENT_ROUTE_FILES,\n },\n true,\n );\n\n return debugRoutes as (Route & DebugRoute)[];\n },\n });\n\nexport type DebugRoute = {\n path: string;\n filename: string;\n isLayout: boolean;\n children?: DebugRoute[];\n};\n\nexport function injectDebugRoutes(): (Route & DebugRoute)[] {\n return inject(DEBUG_ROUTES);\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@analogjs/router",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.18",
|
|
4
4
|
"description": "Filesystem-based routing for Angular",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Brandon Roberts <robertsbt@gmail.com>",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"url": "https://github.com/sponsors/brandonroberts"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@analogjs/content": "^3.0.0-alpha.
|
|
57
|
+
"@analogjs/content": "^3.0.0-alpha.18",
|
|
58
58
|
"@angular/core": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0",
|
|
59
59
|
"@angular/platform-server": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0",
|
|
60
60
|
"@angular/router": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"tslib": "^2.0.0"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
|
-
"@analogjs/vite-plugin-angular": "^3.0.0-alpha.
|
|
80
|
+
"@analogjs/vite-plugin-angular": "^3.0.0-alpha.18"
|
|
81
81
|
},
|
|
82
82
|
"ng-update": {
|
|
83
83
|
"packageGroup": [
|