alepha 0.15.3 → 0.15.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/audits/index.d.ts +332 -332
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +8 -0
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.js +1 -0
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +151 -151
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +3 -0
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +195 -195
- package/dist/api/keys/index.d.ts.map +1 -1
- package/dist/api/notifications/index.browser.js +1 -0
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.js +1 -0
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.d.ts +260 -260
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +10 -0
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.d.ts +10 -10
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +11 -0
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +128 -128
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/batch/index.d.ts +4 -4
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +19 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/email/index.d.ts +13 -13
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +10554 -2
- package/dist/email/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +6 -1
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js +9 -1
- package/dist/lock/core/index.js.map +1 -1
- package/dist/react/auth/index.browser.js +2 -1
- package/dist/react/auth/index.browser.js.map +1 -1
- package/dist/react/auth/index.js +2 -1
- package/dist/react/auth/index.js.map +1 -1
- package/dist/react/core/index.d.ts +3 -3
- package/dist/react/router/index.d.ts +10 -0
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +16 -6
- package/dist/react/router/index.js.map +1 -1
- package/dist/redis/index.d.ts +19 -19
- package/dist/scheduler/index.d.ts +13 -1
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +42 -4
- package/dist/scheduler/index.js.map +1 -1
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +1 -0
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/core/index.d.ts +9 -9
- package/dist/server/links/index.js +1 -1
- package/dist/server/links/index.js.map +1 -1
- package/dist/vite/index.d.ts +2 -1
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +28 -2
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts +34 -34
- package/dist/websocket/index.d.ts.map +1 -1
- package/package.json +6 -3
- package/src/api/audits/controllers/AdminAuditController.ts +8 -0
- package/src/api/files/controllers/AdminFileStatsController.ts +1 -0
- package/src/api/jobs/controllers/AdminJobController.ts +3 -0
- package/src/api/notifications/controllers/AdminNotificationController.ts +1 -0
- package/src/api/parameters/controllers/AdminConfigController.ts +10 -0
- package/src/api/users/controllers/AdminIdentityController.ts +3 -0
- package/src/api/users/controllers/AdminSessionController.ts +3 -0
- package/src/api/users/controllers/AdminUserController.ts +5 -0
- package/src/cli/commands/build.ts +1 -0
- package/src/cli/providers/ViteDevServerProvider.ts +31 -0
- package/src/email/index.workerd.ts +36 -0
- package/src/email/providers/WorkermailerEmailProvider.ts +221 -0
- package/src/lock/core/primitives/$lock.ts +13 -1
- package/src/react/auth/services/ReactAuth.ts +3 -1
- package/src/react/router/atoms/ssrManifestAtom.ts +7 -0
- package/src/react/router/providers/ReactServerProvider.ts +14 -4
- package/src/react/router/providers/SSRManifestProvider.ts +7 -0
- package/src/scheduler/index.workerd.ts +43 -0
- package/src/scheduler/providers/CronProvider.ts +53 -6
- package/src/scheduler/providers/WorkerdCronProvider.ts +102 -0
- package/src/server/compress/providers/ServerCompressProvider.ts +6 -0
- package/src/server/links/providers/ServerLinksProvider.spec.ts +332 -0
- package/src/server/links/providers/ServerLinksProvider.ts +1 -1
- package/src/vite/tasks/generateCloudflare.ts +38 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as alepha19 from "alepha";
|
|
2
2
|
import { Alepha, AlephaError, Async, CompiledEventExecutor, FileLike, Hooks, KIND, Primitive, Static, StreamLike, TArray, TFile, TObject, TRecord, TSchema, TStream, TString, TVoid } from "alepha";
|
|
3
|
-
import * as
|
|
3
|
+
import * as alepha_logger6 from "alepha/logger";
|
|
4
4
|
import { Readable } from "node:stream";
|
|
5
5
|
import { DateTimeProvider, DurationLike } from "alepha/datetime";
|
|
6
6
|
import { ReadableStream } from "node:stream/web";
|
|
@@ -311,7 +311,7 @@ declare class ServerRequestParser {
|
|
|
311
311
|
//#region ../../src/server/core/providers/ServerTimingProvider.d.ts
|
|
312
312
|
type TimingMap = Record<string, [number, number]>;
|
|
313
313
|
declare class ServerTimingProvider {
|
|
314
|
-
protected readonly log:
|
|
314
|
+
protected readonly log: alepha_logger6.Logger;
|
|
315
315
|
protected readonly alepha: Alepha;
|
|
316
316
|
options: {
|
|
317
317
|
prefix: string;
|
|
@@ -335,7 +335,7 @@ declare class ServerTimingProvider {
|
|
|
335
335
|
* - $page => React route (for React SSR)
|
|
336
336
|
*/
|
|
337
337
|
declare class ServerRouterProvider extends RouterProvider<ServerRouteMatcher> {
|
|
338
|
-
protected readonly log:
|
|
338
|
+
protected readonly log: alepha_logger6.Logger;
|
|
339
339
|
protected readonly alepha: Alepha;
|
|
340
340
|
protected readonly routes: ServerRoute[];
|
|
341
341
|
protected readonly serverTimingProvider: ServerTimingProvider;
|
|
@@ -426,7 +426,7 @@ declare class ServerRouterProvider extends RouterProvider<ServerRouteMatcher> {
|
|
|
426
426
|
* ServerProvider supports both Node.js HTTP requests and Web (Fetch API) requests.
|
|
427
427
|
*/
|
|
428
428
|
declare class ServerProvider {
|
|
429
|
-
protected readonly log:
|
|
429
|
+
protected readonly log: alepha_logger6.Logger;
|
|
430
430
|
protected readonly alepha: Alepha;
|
|
431
431
|
protected readonly dateTimeProvider: DateTimeProvider;
|
|
432
432
|
protected readonly router: ServerRouterProvider;
|
|
@@ -487,7 +487,7 @@ declare class ServerProvider {
|
|
|
487
487
|
//#endregion
|
|
488
488
|
//#region ../../src/server/core/services/HttpClient.d.ts
|
|
489
489
|
declare class HttpClient {
|
|
490
|
-
protected readonly log:
|
|
490
|
+
protected readonly log: alepha_logger6.Logger;
|
|
491
491
|
protected readonly alepha: Alepha;
|
|
492
492
|
readonly cache: alepha_cache0.CachePrimitiveFn<HttpClientCache, any[]>;
|
|
493
493
|
protected readonly pendingRequests: HttpClientPendingRequests;
|
|
@@ -703,7 +703,7 @@ interface ActionPrimitiveOptions<TConfig extends RequestConfigSchema> extends Om
|
|
|
703
703
|
handler: ServerActionHandler<TConfig>;
|
|
704
704
|
}
|
|
705
705
|
declare class ActionPrimitive<TConfig extends RequestConfigSchema> extends Primitive<ActionPrimitiveOptions<TConfig>> {
|
|
706
|
-
protected readonly log:
|
|
706
|
+
protected readonly log: alepha_logger6.Logger;
|
|
707
707
|
protected readonly env: {
|
|
708
708
|
SERVER_API_PREFIX: string;
|
|
709
709
|
};
|
|
@@ -852,7 +852,7 @@ declare module "alepha" {
|
|
|
852
852
|
declare class BunHttpServerProvider extends ServerProvider {
|
|
853
853
|
protected readonly alepha: Alepha;
|
|
854
854
|
protected readonly dateTimeProvider: DateTimeProvider;
|
|
855
|
-
protected readonly log:
|
|
855
|
+
protected readonly log: alepha_logger6.Logger;
|
|
856
856
|
protected readonly env: {
|
|
857
857
|
SERVER_PORT: number;
|
|
858
858
|
SERVER_HOST: string;
|
|
@@ -877,7 +877,7 @@ declare module "alepha" {
|
|
|
877
877
|
declare class NodeHttpServerProvider extends ServerProvider {
|
|
878
878
|
protected readonly alepha: Alepha;
|
|
879
879
|
protected readonly dateTimeProvider: DateTimeProvider;
|
|
880
|
-
protected readonly log:
|
|
880
|
+
protected readonly log: alepha_logger6.Logger;
|
|
881
881
|
protected readonly env: {
|
|
882
882
|
SERVER_PORT: number;
|
|
883
883
|
SERVER_HOST: string;
|
|
@@ -919,7 +919,7 @@ declare class NodeHttpServerProvider extends ServerProvider {
|
|
|
919
919
|
//#endregion
|
|
920
920
|
//#region ../../src/server/core/providers/ServerLoggerProvider.d.ts
|
|
921
921
|
declare class ServerLoggerProvider {
|
|
922
|
-
protected readonly log:
|
|
922
|
+
protected readonly log: alepha_logger6.Logger;
|
|
923
923
|
protected readonly alepha: Alepha;
|
|
924
924
|
readonly onRequest: alepha19.HookPrimitive<"server:onRequest">;
|
|
925
925
|
readonly onError: alepha19.HookPrimitive<"server:onError">;
|
|
@@ -381,7 +381,7 @@ var ServerLinksProvider = class {
|
|
|
381
381
|
group: action.group,
|
|
382
382
|
schema: action.options.schema,
|
|
383
383
|
requestBodyType: action.getBodyContentType(),
|
|
384
|
-
secured: action.options.secure
|
|
384
|
+
secured: action.options.secure,
|
|
385
385
|
method: action.method === "GET" ? void 0 : action.method,
|
|
386
386
|
prefix: action.prefix,
|
|
387
387
|
path: action.path,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["envSchema"],"sources":["../../../src/server/links/schemas/apiLinksResponseSchema.ts","../../../src/server/links/atoms/apiLinksAtom.ts","../../../src/server/links/providers/LinkProvider.ts","../../../src/server/links/primitives/$client.ts","../../../src/server/links/primitives/$remote.ts","../../../src/server/links/providers/RemotePrimitiveProvider.ts","../../../src/server/links/providers/ServerLinksProvider.ts","../../../src/server/links/index.ts"],"sourcesContent":["import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\n\nexport const apiLinkSchema = t.object({\n name: t.text({\n description: \"Name of the API link, used for identification.\",\n }),\n\n group: t.optional(\n t.text({\n description:\n \"Group to which the API link belongs, used for categorization.\",\n }),\n ),\n\n path: t.text({\n description: \"Pathname used to access the API link.\",\n }),\n\n method: t.optional(\n t.text({\n description:\n \"HTTP method used for the API link, e.g., GET, POST, etc. If not specified, defaults to GET.\",\n }),\n ),\n\n requestBodyType: t.optional(\n t.text({\n description:\n \"Type of the request body for the API link. Default is application/json for POST/PUT/PATCH, null for others.\",\n }),\n ),\n\n service: t.optional(\n t.text({\n description:\n \"Service name associated with the API link, used for service discovery.\",\n }),\n ),\n\n rawSchema: t.optional(\n t.object({\n body: t.optional(t.string()),\n response: t.optional(t.string()),\n }),\n ),\n});\n\nexport const apiLinksResponseSchema = t.object({\n prefix: t.optional(t.text()),\n links: t.array(apiLinkSchema),\n});\n\nexport type ApiLinksResponse = Static<typeof apiLinksResponseSchema>;\nexport type ApiLink = Static<typeof apiLinkSchema>;\n","import { $atom, t } from \"alepha\";\nimport { apiLinksResponseSchema } from \"../schemas/apiLinksResponseSchema.ts\";\n\nexport const apiLinksAtom = $atom({\n name: \"alepha.server.request.apiLinks\",\n schema: t.optional(apiLinksResponseSchema),\n});\n","import {\n $inject,\n Alepha,\n AlephaError,\n type Async,\n jsonSchemaToTypeBox,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { ServerRouteSecure } from \"alepha/security\";\nimport {\n type ActionPrimitive,\n type ClientRequestEntry,\n type ClientRequestOptions,\n type ClientRequestResponse,\n type FetchResponse,\n HttpClient,\n type RequestConfigSchema,\n ServerReply,\n type ServerRequest,\n type ServerRequestConfigEntry,\n type ServerResponseBody,\n type TRequestBody,\n UnauthorizedError,\n} from \"alepha/server\";\nimport {\n type ApiLink,\n apiLinksResponseSchema,\n} from \"../schemas/apiLinksResponseSchema.ts\";\n\n/**\n * Browser, SSR friendly, service to handle links.\n */\nexport class LinkProvider {\n static path = {\n apiLinks: \"/api/_links\",\n };\n\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly httpClient = $inject(HttpClient);\n\n // all server links (local + remote)\n // THIS IS NOT USER LINKS! (which are filtered by permissions)\n protected serverLinks: Array<HttpClientLink> = [];\n\n /**\n * Get applicative links registered on the server.\n * This does not include lazy-loaded remote links.\n */\n public getServerLinks(): HttpClientLink[] {\n if (this.alepha.isBrowser()) {\n this.log.warn(\n \"Getting server links in the browser is not supported. Use `fetchLinks` to get links from the server.\",\n );\n return [];\n }\n\n return this.serverLinks;\n }\n\n /**\n * Register a new link for the application.\n */\n public registerLink(link: HttpClientLink): void {\n if (this.alepha.isBrowser()) {\n this.log.warn(\n \"Registering links in the browser is not supported. Use `fetchLinks` to get links from the server.\",\n );\n return;\n }\n\n if (!link.handler && !link.host) {\n throw new AlephaError(\n \"Can't create link - 'handler' or 'host' is required\",\n );\n }\n\n if (this.serverLinks.some((l) => l.name === link.name)) {\n // remove existing link with the same name\n this.serverLinks = this.serverLinks.filter((l) => l.name !== link.name);\n }\n\n if (!link.rawSchema) {\n link.rawSchema = {};\n if (link.schema?.body)\n link.rawSchema.body = JSON.stringify(link.schema.body);\n if (link.schema?.response)\n link.rawSchema.response = JSON.stringify(link.schema.response);\n }\n\n this.serverLinks.push(link);\n }\n\n public get links(): HttpClientLink[] {\n // TODO: not performant at all, use a map instead for ServerLinks\n const apiLinks = this.alepha.store.get(\n \"alepha.server.request.apiLinks\",\n )?.links;\n\n if (apiLinks) {\n if (this.alepha.isBrowser()) {\n return apiLinks;\n }\n\n const links = [];\n for (const link of apiLinks) {\n const originalLink = this.serverLinks.find((l) => l.name === link.name);\n if (originalLink) {\n links.push(originalLink);\n }\n }\n return links;\n }\n\n return this.serverLinks ?? [];\n }\n\n /**\n * Force browser to refresh links from the server.\n */\n public async fetchLinks(): Promise<HttpClientLink[]> {\n const { data } = await this.httpClient.fetch(\n `${LinkProvider.path.apiLinks}`,\n {\n method: \"GET\",\n schema: {\n response: apiLinksResponseSchema,\n },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data);\n\n return data.links;\n }\n\n /**\n * Create a virtual client that can be used to call actions.\n *\n * Use js Proxy under the hood.\n */\n public client<T extends object>(\n scope: ClientScope = {},\n ): HttpVirtualClient<T> {\n return new Proxy<HttpVirtualClient<T>>({} as HttpVirtualClient<T>, {\n get: (_, prop) => {\n if (typeof prop !== \"string\") {\n return;\n }\n\n return this.createVirtualAction<RequestConfigSchema>(prop, scope);\n },\n });\n }\n\n /**\n * Check if a link with the given name exists.\n * @param name\n */\n public can(name: string): boolean {\n return this.links.some((link) => link.name === name);\n }\n\n /**\n * Resolve a link by its name and call it.\n * - If link is local, it will call the local handler.\n * - If link is remote, it will make a fetch request to the remote server.\n */\n public async follow(\n name: string,\n config: Partial<ServerRequestConfigEntry> = {},\n options: ClientRequestOptions & ClientScope = {},\n ): Promise<any> {\n this.log.trace(\"Following link\", { name, config, options });\n const link = await this.getLinkByName(name, options);\n\n // if a handler is defined, use it (ssr)\n if (link.handler && !options.request) {\n this.log.trace(\"Local link found\", { name });\n return link.handler(\n {\n method: link.method,\n url: new URL(`http://localhost${link.path}`),\n query: config.query ?? {},\n body: config.body ?? {},\n params: config.params ?? {},\n headers: config.headers ?? {},\n metadata: {},\n reply: new ServerReply(),\n } as Partial<ServerRequest> as ServerRequest,\n options,\n );\n }\n\n this.log.trace(\"Remote link found\", {\n name,\n host: link.host,\n service: link.service,\n });\n\n return this.followRemote(link, config, options).then(\n (response) => response.data,\n );\n }\n\n protected createVirtualAction<T extends RequestConfigSchema>(\n name: string,\n scope: ClientScope = {},\n ): VirtualAction<T> {\n const $: VirtualAction<T> = async (\n config: any = {},\n options: ClientRequestOptions = {},\n ) => {\n return this.follow(name, config, {\n ...scope,\n ...options,\n });\n };\n\n Object.defineProperty($, \"name\", {\n value: name,\n writable: false,\n });\n\n $.run = async (config: any = {}, options: ClientRequestOptions = {}) => {\n return this.follow(name, config, {\n ...scope,\n ...options,\n });\n };\n\n $.fetch = async (config: any = {}, options: ClientRequestOptions = {}) => {\n const link = await this.getLinkByName(name, scope);\n return this.followRemote(link, config, options);\n };\n\n $.can = () => {\n return this.can(name);\n };\n\n $.schema = () => {\n const link = this.links.find((l) => l.name === name);\n if (!link) {\n throw new AlephaError(`Link ${name} not found.`);\n }\n\n if (link.rawSchema && !link.schema) {\n link.schema = {};\n link.schema.body = link.rawSchema?.body\n ? (jsonSchemaToTypeBox(\n JSON.parse(link.rawSchema.body),\n ) as TRequestBody)\n : undefined;\n link.schema.response = link.rawSchema?.response\n ? (jsonSchemaToTypeBox(\n JSON.parse(link.rawSchema.response),\n ) as TRequestBody)\n : undefined;\n }\n\n return link.schema as {\n body: any;\n response: any;\n };\n };\n\n return $;\n }\n\n protected async followRemote(\n link: HttpClientLink,\n config: Partial<ServerRequestConfigEntry> = {},\n options: ClientRequestOptions = {},\n ): Promise<FetchResponse> {\n options.request ??= {};\n options.request.headers = new Headers(options.request.headers);\n\n const als = this.alepha.context.get<ServerRequest>(\"request\");\n if (als?.headers.authorization) {\n options.request.headers.set(\"authorization\", als.headers.authorization);\n }\n\n const context = this.alepha.context.get(\"context\");\n if (typeof context === \"string\") {\n options.request.headers.set(\"x-request-id\", context);\n }\n\n const action = {\n ...link,\n // schema is not used in the client,\n // we assume that TypeScript will check\n schema: {\n body: t.any(),\n response: t.any(),\n },\n };\n\n // prefix with service when host is not defined (e.g. browser)\n if (!link.host && link.service) {\n action.path = `/${link.service}${action.path}`;\n }\n\n action.path = `${action.prefix ?? \"/api\"}${action.path}`;\n action.prefix = undefined; // prefix is not used in the client\n\n // else, make a request\n return this.httpClient.fetchAction({\n host: link.host,\n config,\n options,\n action: action as any, // schema.body TAny is not accepted\n });\n }\n\n protected async getLinkByName(\n name: string,\n options: ClientScope = {},\n ): Promise<HttpClientLink> {\n if (\n this.alepha.isBrowser() &&\n !this.alepha.store.get(\"alepha.server.request.apiLinks\")\n ) {\n await this.fetchLinks();\n }\n\n const link = this.links.find(\n (a) =>\n a.name === name &&\n (!options.group || a.group === options.group) &&\n (!options.service || options.service === a.service),\n );\n\n if (!link) {\n const error = new UnauthorizedError(`Action ${name} not found.`);\n // mimic http error handling\n await this.alepha.events.emit(\"client:onError\", {\n route: link,\n error,\n });\n throw error;\n }\n\n if (options.hostname) {\n return {\n ...link,\n host: options.hostname,\n };\n }\n\n return link;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface HttpClientLink extends ApiLink {\n secured?: boolean | ServerRouteSecure;\n prefix?: string;\n // -- server only --\n // only for remote actions\n host?: string;\n service?: string;\n // used only for local actions, not for remote actions\n schema?: RequestConfigSchema;\n handler?: (\n request: ServerRequest,\n options: ClientRequestOptions,\n ) => Async<ServerResponseBody>;\n}\n\nexport interface ClientScope {\n group?: string;\n service?: string;\n hostname?: string;\n}\n\nexport type HttpVirtualClient<T> = {\n [K in keyof T as T[K] extends ActionPrimitive<RequestConfigSchema>\n ? K\n : never]: T[K] extends ActionPrimitive<infer Schema>\n ? VirtualAction<Schema>\n : never;\n};\n\nexport interface VirtualAction<T extends RequestConfigSchema>\n extends Pick<ActionPrimitive<T>, \"name\" | \"run\" | \"fetch\"> {\n (\n config?: ClientRequestEntry<T>,\n opts?: ClientRequestOptions,\n ): Promise<ClientRequestResponse<T>>;\n can: () => boolean;\n schema: () => {\n body: T[\"body\"];\n response: T[\"response\"];\n };\n}\n","import { $inject, KIND } from \"alepha\";\nimport {\n type ClientScope,\n type HttpVirtualClient,\n LinkProvider,\n} from \"../providers/LinkProvider.ts\";\n\n/**\n * Create a new client.\n */\nexport const $client = <T extends object>(\n scope?: ClientScope,\n): HttpVirtualClient<T> => {\n return $inject(LinkProvider).client<T>(scope);\n};\n\n$client[KIND] = \"$client\";\n","import { createPrimitive, KIND, Primitive } from \"alepha\";\nimport type { ServiceAccountPrimitive } from \"alepha/security\";\nimport type { ProxyPrimitiveOptions } from \"alepha/server/proxy\";\n\n/**\n * $remote is a primitive that allows you to define remote service access.\n *\n * Use it only when you have 2 or more services that need to communicate with each other.\n *\n * All remote services can be exposed as actions, ... or not.\n *\n * You can add a service account if you want to use a security layer.\n */\nexport const $remote = (options: RemotePrimitiveOptions) => {\n return createPrimitive(RemotePrimitive, options);\n};\n\nexport interface RemotePrimitiveOptions {\n /**\n * The URL of the remote service.\n * You can use a function to generate the URL dynamically.\n * You probably should use $env(env) to get the URL from the environment.\n *\n * @example\n * ```ts\n * import { $remote } from \"alepha/server\";\n * import { $inject, t } from \"alepha\";\n *\n * class App {\n * env = $env(t.object({\n * REMOTE_URL: t.text({default: \"http://localhost:3000\"}),\n * }));\n * remote = $remote({\n * url: this.env.REMOTE_URL,\n * });\n * }\n * ```\n */\n url: string | (() => string);\n\n /**\n * The name of the remote service.\n *\n * @default Member of the class containing the remote service.\n */\n name?: string;\n\n /**\n * If true, all methods of the remote service will be exposed as actions in this context.\n * > Note: Proxy will never use the service account, it just... proxies the request.\n */\n proxy?:\n | boolean\n | Partial<\n ProxyPrimitiveOptions & {\n /**\n * If true, the remote service won't be available internally, only through the proxy.\n */\n noInternal: boolean;\n }\n >;\n\n /**\n * For communication between the server and the remote service with a security layer.\n * This will be used for internal communication and will not be exposed to the client.\n */\n serviceAccount?: ServiceAccountPrimitive;\n}\n\nexport class RemotePrimitive extends Primitive<RemotePrimitiveOptions> {\n public get name(): string {\n return this.options.name ?? this.config.propertyKey;\n }\n}\n\n$remote[KIND] = RemotePrimitive;\n","import { $env, $hook, $inject, Alepha, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { $retry } from \"alepha/retry\";\nimport type { ServiceAccountPrimitive } from \"alepha/security\";\nimport { ServerProxyProvider } from \"alepha/server/proxy\";\nimport { $remote, type RemotePrimitive } from \"../primitives/$remote.ts\";\nimport {\n type ApiLinksResponse,\n apiLinksResponseSchema,\n} from \"../schemas/apiLinksResponseSchema.ts\";\nimport { LinkProvider } from \"./LinkProvider.ts\";\n\nconst envSchema = t.object({\n SERVER_API_PREFIX: t.text({\n description: \"Prefix for all API routes (e.g. $action).\",\n default: \"/api\",\n }),\n});\n\nexport class RemotePrimitiveProvider {\n protected readonly env = $env(envSchema);\n protected readonly alepha = $inject(Alepha);\n protected readonly proxyProvider = $inject(ServerProxyProvider);\n protected readonly linkProvider = $inject(LinkProvider);\n protected readonly remotes: Array<ServerRemote> = [];\n protected readonly log = $logger();\n\n public getRemotes(): ServerRemote[] {\n return this.remotes;\n }\n\n public readonly configure = $hook({\n on: \"configure\",\n handler: async () => {\n const remotes = this.alepha.primitives($remote);\n for (const remote of remotes) {\n await this.registerRemote(remote);\n }\n },\n });\n\n public readonly start = $hook({\n on: \"start\",\n handler: async () => {\n for (const remote of this.remotes) {\n const token =\n typeof remote.serviceAccount?.token === \"function\"\n ? await remote.serviceAccount.token()\n : undefined;\n\n if (!remote.internal) {\n continue; // skip download links for remotes that are not internal\n }\n\n const { links } = await remote.links({ authorization: token });\n\n for (const link of links) {\n let path = link.path.replace(remote.prefix, \"\");\n if (link.service) {\n path = `/${link.service}${path}`;\n }\n\n this.linkProvider.registerLink({\n ...link,\n prefix: remote.prefix,\n path,\n method: link.method ?? \"GET\",\n host: remote.url,\n service: remote.name,\n });\n }\n\n this.log.info(`Remote '${remote.name}' OK`, {\n links: remote.links.length,\n prefix: remote.prefix,\n });\n }\n },\n });\n\n public async registerRemote(value: RemotePrimitive): Promise<void> {\n const options = value.options;\n const url = typeof options.url === \"string\" ? options.url : options.url();\n const linkPath = LinkProvider.path.apiLinks;\n const name = value.name;\n const proxy = typeof options.proxy === \"object\" ? options.proxy : {};\n\n const remote: ServerRemote = {\n url,\n name,\n prefix: \"/api\",\n serviceAccount: options.serviceAccount,\n proxy: !!options.proxy,\n internal: !proxy.noInternal,\n schema: async (opts) => {\n const { authorization, name } = opts;\n return await fetch(`${url}${linkPath}/${name}/schema`, {\n headers: new Headers(\n authorization\n ? {\n authorization,\n }\n : {},\n ),\n }).then((it) => it.json()); // TODO: use schema validation for response\n },\n links: async (opts) => {\n const { authorization } = opts;\n const remoteApi = await this.fetchLinks.run({\n service: name,\n url: `${url}${linkPath}`,\n authorization,\n });\n\n if (remoteApi.prefix != null) {\n remote.prefix = remoteApi.prefix; // monkey patch the prefix, not ideal but works\n }\n\n return remoteApi;\n },\n };\n\n this.remotes.push(remote);\n\n if (options.proxy) {\n this.proxyProvider.createProxy({\n path: `${this.env.SERVER_API_PREFIX}/${name}/*`,\n target: url,\n rewrite: (url) => {\n url.pathname = url.pathname.replace(\n `${this.env.SERVER_API_PREFIX}/${name}`,\n remote.prefix,\n );\n },\n ...proxy,\n });\n }\n }\n\n protected readonly fetchLinks = $retry({\n max: 10,\n backoff: {\n initial: 1000,\n },\n onError: (_, attempt, { service, url }) => {\n this.log.warn(`Failed to fetch links, retry (${attempt})...`, {\n service,\n url,\n });\n },\n handler: async (opts: FetchLinksOptions): Promise<ApiLinksResponse> => {\n const { url, authorization } = opts;\n const response = await fetch(url, {\n headers: new Headers(\n authorization\n ? {\n authorization,\n }\n : {},\n ),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch links from ${url}`);\n }\n\n return this.alepha.codec.decode(\n apiLinksResponseSchema,\n await response.json(),\n );\n },\n });\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface FetchLinksOptions {\n /**\n * Name of the remote service.\n */\n service: string;\n\n /**\n * URL to fetch links from.\n */\n url: string;\n\n /**\n * Authorization header containing access token.\n */\n authorization?: string;\n}\n\nexport interface ServerRemote {\n /**\n * URL of the remote service.\n */\n url: string;\n\n /**\n * Name of the remote service.\n */\n name: string;\n\n /**\n * Expose links as endpoint. It's not only internal.\n */\n proxy: boolean;\n\n /**\n * It's only used inside the application.\n */\n internal: boolean;\n\n /**\n * Links fetcher.\n */\n links: (args: { authorization?: string }) => Promise<ApiLinksResponse>;\n\n /**\n * Fetches schema for the remote service.\n */\n schema: (args: { name: string; authorization?: string }) => Promise<any>;\n\n /**\n * Force a default access token provider when not provided.\n */\n serviceAccount?: ServiceAccountPrimitive;\n\n /**\n * Prefix for the remote service links.\n */\n prefix: string;\n}\n","import { $env, $hook, $inject, Alepha, t } from \"alepha\";\nimport {\n type Permission,\n SecurityProvider,\n type UserAccountToken,\n} from \"alepha/security\";\nimport {\n $action,\n $route,\n type ClientRequestEntry,\n type ClientRequestOptions,\n type RequestConfigSchema,\n ServerTimingProvider,\n} from \"alepha/server\";\nimport {\n type ApiLink,\n type ApiLinksResponse,\n apiLinksResponseSchema,\n} from \"../schemas/apiLinksResponseSchema.ts\";\nimport { LinkProvider } from \"./LinkProvider.ts\";\nimport { RemotePrimitiveProvider } from \"./RemotePrimitiveProvider.ts\";\n\nconst envSchema = t.object({\n SERVER_API_PREFIX: t.text({\n description: \"Prefix for all API routes (e.g. $action).\",\n default: \"/api\",\n }),\n});\n\nexport class ServerLinksProvider {\n protected readonly env = $env(envSchema);\n protected readonly alepha = $inject(Alepha);\n protected readonly linkProvider = $inject(LinkProvider);\n protected readonly remoteProvider = $inject(RemotePrimitiveProvider);\n protected readonly serverTimingProvider = $inject(ServerTimingProvider);\n\n public get prefix() {\n return this.env.SERVER_API_PREFIX;\n }\n\n public readonly onRoute = $hook({\n on: \"configure\",\n handler: () => {\n // convert all $action to local links\n for (const action of this.alepha.primitives($action)) {\n this.linkProvider.registerLink({\n name: action.name,\n group: action.group,\n schema: action.options.schema,\n requestBodyType: action.getBodyContentType(),\n secured: action.options.secure ?? true,\n method: action.method === \"GET\" ? undefined : action.method,\n prefix: action.prefix,\n path: action.path,\n // by local, we mean that it can be called directly via the handler\n handler: (\n config: ClientRequestEntry<RequestConfigSchema>,\n options: ClientRequestOptions = {},\n ) => action.run(config, options),\n });\n }\n },\n });\n\n /**\n * First API - Get all API links for the user.\n *\n * This is based on the user's permissions.\n */\n public readonly links = $route({\n path: LinkProvider.path.apiLinks,\n schema: {\n response: apiLinksResponseSchema,\n },\n handler: ({ user, headers }) => {\n return this.getUserApiLinks({\n user,\n authorization: headers.authorization,\n });\n },\n });\n\n /**\n * Retrieves API links for the user based on their permissions.\n * Will check on local links and remote links.\n */\n public async getUserApiLinks(\n options: GetApiLinksOptions,\n ): Promise<ApiLinksResponse> {\n const { user } = options;\n let permissions: Permission[] | undefined;\n let permissionMap: Map<string, Permission> | undefined;\n const hasSecurity = this.alepha.has(SecurityProvider);\n if (hasSecurity && user) {\n permissions = this.alepha.inject(SecurityProvider).getPermissions(user);\n permissionMap = new Map(\n permissions.map((it) => [`${it.group}:${it.name}`, it]),\n );\n }\n\n const userLinks: ApiLink[] = [];\n\n // bonus: add permissions not related to $action\n for (const permission of permissions ?? []) {\n if (\n !permission.path &&\n !permission.method &&\n permission.name &&\n permission.group\n ) {\n userLinks.push({\n path: \"\", // this is a placeholder for links without specific path\n name: permission.name,\n group: permission.group,\n });\n }\n }\n\n // add local links\n for (const link of this.linkProvider.getServerLinks()) {\n // SKIP REMOTE LINKS, remote links are handled separately for security\n if (link.host) continue;\n\n if (hasSecurity && link.secured) {\n // skip secured links if user is not provided\n if (!user) {\n continue;\n }\n\n if (typeof link.secured === \"object\" && link.secured.realm) {\n // realm check\n if (user.realm !== link.secured.realm) {\n continue;\n }\n } else if (permissionMap) {\n // small permissions check, can be optimized later ... :')\n\n if (!permissionMap.has(`${link.group}:${link.name}`)) {\n continue;\n }\n }\n }\n\n userLinks.push({\n name: link.name,\n group: link.group,\n requestBodyType: link.requestBodyType,\n method: link.method,\n path: link.path,\n rawSchema: link.rawSchema,\n });\n }\n\n this.serverTimingProvider.beginTiming(\"fetchRemoteLinks\");\n // this does not scale well, but it's working for now\n // TODO: remote links can be cached by user.roles\n const promises = this.remoteProvider\n .getRemotes()\n .filter((it) => it.proxy) // add only \"proxy\" remotes\n .map(async (remote) => {\n const { links, prefix } = await remote.links(options);\n return links.map((link) => {\n let path = link.path.replace(prefix ?? \"/api\", \"\");\n if (link.service) {\n path = `/${link.service}${path}`;\n }\n\n return {\n ...link,\n path,\n proxy: true,\n service: remote.name,\n };\n });\n });\n\n userLinks.push(...(await Promise.all(promises)).flat());\n this.serverTimingProvider.endTiming(\"fetchRemoteLinks\");\n\n return {\n prefix: this.env.SERVER_API_PREFIX,\n links: userLinks,\n };\n }\n}\n\nexport interface GetApiLinksOptions {\n user?: UserAccountToken;\n authorization?: string;\n}\n","import \"alepha/security\";\nimport { $module } from \"alepha\";\nimport { AlephaServer } from \"alepha/server\";\nimport { apiLinksAtom } from \"./atoms/apiLinksAtom.ts\";\nimport { $client } from \"./primitives/$client.ts\";\nimport { $remote } from \"./primitives/$remote.ts\";\nimport { LinkProvider } from \"./providers/LinkProvider.ts\";\nimport { RemotePrimitiveProvider } from \"./providers/RemotePrimitiveProvider.ts\";\nimport { ServerLinksProvider } from \"./providers/ServerLinksProvider.ts\";\nimport type { ApiLinksResponse } from \"./schemas/apiLinksResponseSchema.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./primitives/$client.ts\";\nexport * from \"./primitives/$remote.ts\";\nexport * from \"./providers/LinkProvider.ts\";\nexport * from \"./providers/RemotePrimitiveProvider.ts\";\nexport * from \"./providers/ServerLinksProvider.ts\";\nexport * from \"./schemas/apiLinksResponseSchema.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface State {\n /**\n * API links attached to the server request state.\n *\n * @see {@link ApiLinksResponse}\n * @internal\n */\n \"alepha.server.request.apiLinks\"?: ApiLinksResponse;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * | type | quality | stability |\n * |------|---------|-----------|\n * | backend | standard | stable |\n *\n * Type-safe API client with request deduplication.\n *\n * **Features:**\n * - Virtual HTTP client for type-safe API calls\n * - Remote action definitions\n * - Type inference from action schemas\n * - Request deduplication\n * - Automatic error handling\n *\n * @module alepha.server.links\n */\nexport const AlephaServerLinks = $module({\n name: \"alepha.server.links\",\n atoms: [apiLinksAtom],\n primitives: [$remote, $client],\n services: [\n AlephaServer,\n ServerLinksProvider,\n RemotePrimitiveProvider,\n LinkProvider,\n ],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["envSchema"],"sources":["../../../src/server/links/schemas/apiLinksResponseSchema.ts","../../../src/server/links/atoms/apiLinksAtom.ts","../../../src/server/links/providers/LinkProvider.ts","../../../src/server/links/primitives/$client.ts","../../../src/server/links/primitives/$remote.ts","../../../src/server/links/providers/RemotePrimitiveProvider.ts","../../../src/server/links/providers/ServerLinksProvider.ts","../../../src/server/links/index.ts"],"sourcesContent":["import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\n\nexport const apiLinkSchema = t.object({\n name: t.text({\n description: \"Name of the API link, used for identification.\",\n }),\n\n group: t.optional(\n t.text({\n description:\n \"Group to which the API link belongs, used for categorization.\",\n }),\n ),\n\n path: t.text({\n description: \"Pathname used to access the API link.\",\n }),\n\n method: t.optional(\n t.text({\n description:\n \"HTTP method used for the API link, e.g., GET, POST, etc. If not specified, defaults to GET.\",\n }),\n ),\n\n requestBodyType: t.optional(\n t.text({\n description:\n \"Type of the request body for the API link. Default is application/json for POST/PUT/PATCH, null for others.\",\n }),\n ),\n\n service: t.optional(\n t.text({\n description:\n \"Service name associated with the API link, used for service discovery.\",\n }),\n ),\n\n rawSchema: t.optional(\n t.object({\n body: t.optional(t.string()),\n response: t.optional(t.string()),\n }),\n ),\n});\n\nexport const apiLinksResponseSchema = t.object({\n prefix: t.optional(t.text()),\n links: t.array(apiLinkSchema),\n});\n\nexport type ApiLinksResponse = Static<typeof apiLinksResponseSchema>;\nexport type ApiLink = Static<typeof apiLinkSchema>;\n","import { $atom, t } from \"alepha\";\nimport { apiLinksResponseSchema } from \"../schemas/apiLinksResponseSchema.ts\";\n\nexport const apiLinksAtom = $atom({\n name: \"alepha.server.request.apiLinks\",\n schema: t.optional(apiLinksResponseSchema),\n});\n","import {\n $inject,\n Alepha,\n AlephaError,\n type Async,\n jsonSchemaToTypeBox,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { ServerRouteSecure } from \"alepha/security\";\nimport {\n type ActionPrimitive,\n type ClientRequestEntry,\n type ClientRequestOptions,\n type ClientRequestResponse,\n type FetchResponse,\n HttpClient,\n type RequestConfigSchema,\n ServerReply,\n type ServerRequest,\n type ServerRequestConfigEntry,\n type ServerResponseBody,\n type TRequestBody,\n UnauthorizedError,\n} from \"alepha/server\";\nimport {\n type ApiLink,\n apiLinksResponseSchema,\n} from \"../schemas/apiLinksResponseSchema.ts\";\n\n/**\n * Browser, SSR friendly, service to handle links.\n */\nexport class LinkProvider {\n static path = {\n apiLinks: \"/api/_links\",\n };\n\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly httpClient = $inject(HttpClient);\n\n // all server links (local + remote)\n // THIS IS NOT USER LINKS! (which are filtered by permissions)\n protected serverLinks: Array<HttpClientLink> = [];\n\n /**\n * Get applicative links registered on the server.\n * This does not include lazy-loaded remote links.\n */\n public getServerLinks(): HttpClientLink[] {\n if (this.alepha.isBrowser()) {\n this.log.warn(\n \"Getting server links in the browser is not supported. Use `fetchLinks` to get links from the server.\",\n );\n return [];\n }\n\n return this.serverLinks;\n }\n\n /**\n * Register a new link for the application.\n */\n public registerLink(link: HttpClientLink): void {\n if (this.alepha.isBrowser()) {\n this.log.warn(\n \"Registering links in the browser is not supported. Use `fetchLinks` to get links from the server.\",\n );\n return;\n }\n\n if (!link.handler && !link.host) {\n throw new AlephaError(\n \"Can't create link - 'handler' or 'host' is required\",\n );\n }\n\n if (this.serverLinks.some((l) => l.name === link.name)) {\n // remove existing link with the same name\n this.serverLinks = this.serverLinks.filter((l) => l.name !== link.name);\n }\n\n if (!link.rawSchema) {\n link.rawSchema = {};\n if (link.schema?.body)\n link.rawSchema.body = JSON.stringify(link.schema.body);\n if (link.schema?.response)\n link.rawSchema.response = JSON.stringify(link.schema.response);\n }\n\n this.serverLinks.push(link);\n }\n\n public get links(): HttpClientLink[] {\n // TODO: not performant at all, use a map instead for ServerLinks\n const apiLinks = this.alepha.store.get(\n \"alepha.server.request.apiLinks\",\n )?.links;\n\n if (apiLinks) {\n if (this.alepha.isBrowser()) {\n return apiLinks;\n }\n\n const links = [];\n for (const link of apiLinks) {\n const originalLink = this.serverLinks.find((l) => l.name === link.name);\n if (originalLink) {\n links.push(originalLink);\n }\n }\n return links;\n }\n\n return this.serverLinks ?? [];\n }\n\n /**\n * Force browser to refresh links from the server.\n */\n public async fetchLinks(): Promise<HttpClientLink[]> {\n const { data } = await this.httpClient.fetch(\n `${LinkProvider.path.apiLinks}`,\n {\n method: \"GET\",\n schema: {\n response: apiLinksResponseSchema,\n },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data);\n\n return data.links;\n }\n\n /**\n * Create a virtual client that can be used to call actions.\n *\n * Use js Proxy under the hood.\n */\n public client<T extends object>(\n scope: ClientScope = {},\n ): HttpVirtualClient<T> {\n return new Proxy<HttpVirtualClient<T>>({} as HttpVirtualClient<T>, {\n get: (_, prop) => {\n if (typeof prop !== \"string\") {\n return;\n }\n\n return this.createVirtualAction<RequestConfigSchema>(prop, scope);\n },\n });\n }\n\n /**\n * Check if a link with the given name exists.\n * @param name\n */\n public can(name: string): boolean {\n return this.links.some((link) => link.name === name);\n }\n\n /**\n * Resolve a link by its name and call it.\n * - If link is local, it will call the local handler.\n * - If link is remote, it will make a fetch request to the remote server.\n */\n public async follow(\n name: string,\n config: Partial<ServerRequestConfigEntry> = {},\n options: ClientRequestOptions & ClientScope = {},\n ): Promise<any> {\n this.log.trace(\"Following link\", { name, config, options });\n const link = await this.getLinkByName(name, options);\n\n // if a handler is defined, use it (ssr)\n if (link.handler && !options.request) {\n this.log.trace(\"Local link found\", { name });\n return link.handler(\n {\n method: link.method,\n url: new URL(`http://localhost${link.path}`),\n query: config.query ?? {},\n body: config.body ?? {},\n params: config.params ?? {},\n headers: config.headers ?? {},\n metadata: {},\n reply: new ServerReply(),\n } as Partial<ServerRequest> as ServerRequest,\n options,\n );\n }\n\n this.log.trace(\"Remote link found\", {\n name,\n host: link.host,\n service: link.service,\n });\n\n return this.followRemote(link, config, options).then(\n (response) => response.data,\n );\n }\n\n protected createVirtualAction<T extends RequestConfigSchema>(\n name: string,\n scope: ClientScope = {},\n ): VirtualAction<T> {\n const $: VirtualAction<T> = async (\n config: any = {},\n options: ClientRequestOptions = {},\n ) => {\n return this.follow(name, config, {\n ...scope,\n ...options,\n });\n };\n\n Object.defineProperty($, \"name\", {\n value: name,\n writable: false,\n });\n\n $.run = async (config: any = {}, options: ClientRequestOptions = {}) => {\n return this.follow(name, config, {\n ...scope,\n ...options,\n });\n };\n\n $.fetch = async (config: any = {}, options: ClientRequestOptions = {}) => {\n const link = await this.getLinkByName(name, scope);\n return this.followRemote(link, config, options);\n };\n\n $.can = () => {\n return this.can(name);\n };\n\n $.schema = () => {\n const link = this.links.find((l) => l.name === name);\n if (!link) {\n throw new AlephaError(`Link ${name} not found.`);\n }\n\n if (link.rawSchema && !link.schema) {\n link.schema = {};\n link.schema.body = link.rawSchema?.body\n ? (jsonSchemaToTypeBox(\n JSON.parse(link.rawSchema.body),\n ) as TRequestBody)\n : undefined;\n link.schema.response = link.rawSchema?.response\n ? (jsonSchemaToTypeBox(\n JSON.parse(link.rawSchema.response),\n ) as TRequestBody)\n : undefined;\n }\n\n return link.schema as {\n body: any;\n response: any;\n };\n };\n\n return $;\n }\n\n protected async followRemote(\n link: HttpClientLink,\n config: Partial<ServerRequestConfigEntry> = {},\n options: ClientRequestOptions = {},\n ): Promise<FetchResponse> {\n options.request ??= {};\n options.request.headers = new Headers(options.request.headers);\n\n const als = this.alepha.context.get<ServerRequest>(\"request\");\n if (als?.headers.authorization) {\n options.request.headers.set(\"authorization\", als.headers.authorization);\n }\n\n const context = this.alepha.context.get(\"context\");\n if (typeof context === \"string\") {\n options.request.headers.set(\"x-request-id\", context);\n }\n\n const action = {\n ...link,\n // schema is not used in the client,\n // we assume that TypeScript will check\n schema: {\n body: t.any(),\n response: t.any(),\n },\n };\n\n // prefix with service when host is not defined (e.g. browser)\n if (!link.host && link.service) {\n action.path = `/${link.service}${action.path}`;\n }\n\n action.path = `${action.prefix ?? \"/api\"}${action.path}`;\n action.prefix = undefined; // prefix is not used in the client\n\n // else, make a request\n return this.httpClient.fetchAction({\n host: link.host,\n config,\n options,\n action: action as any, // schema.body TAny is not accepted\n });\n }\n\n protected async getLinkByName(\n name: string,\n options: ClientScope = {},\n ): Promise<HttpClientLink> {\n if (\n this.alepha.isBrowser() &&\n !this.alepha.store.get(\"alepha.server.request.apiLinks\")\n ) {\n await this.fetchLinks();\n }\n\n const link = this.links.find(\n (a) =>\n a.name === name &&\n (!options.group || a.group === options.group) &&\n (!options.service || options.service === a.service),\n );\n\n if (!link) {\n const error = new UnauthorizedError(`Action ${name} not found.`);\n // mimic http error handling\n await this.alepha.events.emit(\"client:onError\", {\n route: link,\n error,\n });\n throw error;\n }\n\n if (options.hostname) {\n return {\n ...link,\n host: options.hostname,\n };\n }\n\n return link;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface HttpClientLink extends ApiLink {\n secured?: boolean | ServerRouteSecure;\n prefix?: string;\n // -- server only --\n // only for remote actions\n host?: string;\n service?: string;\n // used only for local actions, not for remote actions\n schema?: RequestConfigSchema;\n handler?: (\n request: ServerRequest,\n options: ClientRequestOptions,\n ) => Async<ServerResponseBody>;\n}\n\nexport interface ClientScope {\n group?: string;\n service?: string;\n hostname?: string;\n}\n\nexport type HttpVirtualClient<T> = {\n [K in keyof T as T[K] extends ActionPrimitive<RequestConfigSchema>\n ? K\n : never]: T[K] extends ActionPrimitive<infer Schema>\n ? VirtualAction<Schema>\n : never;\n};\n\nexport interface VirtualAction<T extends RequestConfigSchema>\n extends Pick<ActionPrimitive<T>, \"name\" | \"run\" | \"fetch\"> {\n (\n config?: ClientRequestEntry<T>,\n opts?: ClientRequestOptions,\n ): Promise<ClientRequestResponse<T>>;\n can: () => boolean;\n schema: () => {\n body: T[\"body\"];\n response: T[\"response\"];\n };\n}\n","import { $inject, KIND } from \"alepha\";\nimport {\n type ClientScope,\n type HttpVirtualClient,\n LinkProvider,\n} from \"../providers/LinkProvider.ts\";\n\n/**\n * Create a new client.\n */\nexport const $client = <T extends object>(\n scope?: ClientScope,\n): HttpVirtualClient<T> => {\n return $inject(LinkProvider).client<T>(scope);\n};\n\n$client[KIND] = \"$client\";\n","import { createPrimitive, KIND, Primitive } from \"alepha\";\nimport type { ServiceAccountPrimitive } from \"alepha/security\";\nimport type { ProxyPrimitiveOptions } from \"alepha/server/proxy\";\n\n/**\n * $remote is a primitive that allows you to define remote service access.\n *\n * Use it only when you have 2 or more services that need to communicate with each other.\n *\n * All remote services can be exposed as actions, ... or not.\n *\n * You can add a service account if you want to use a security layer.\n */\nexport const $remote = (options: RemotePrimitiveOptions) => {\n return createPrimitive(RemotePrimitive, options);\n};\n\nexport interface RemotePrimitiveOptions {\n /**\n * The URL of the remote service.\n * You can use a function to generate the URL dynamically.\n * You probably should use $env(env) to get the URL from the environment.\n *\n * @example\n * ```ts\n * import { $remote } from \"alepha/server\";\n * import { $inject, t } from \"alepha\";\n *\n * class App {\n * env = $env(t.object({\n * REMOTE_URL: t.text({default: \"http://localhost:3000\"}),\n * }));\n * remote = $remote({\n * url: this.env.REMOTE_URL,\n * });\n * }\n * ```\n */\n url: string | (() => string);\n\n /**\n * The name of the remote service.\n *\n * @default Member of the class containing the remote service.\n */\n name?: string;\n\n /**\n * If true, all methods of the remote service will be exposed as actions in this context.\n * > Note: Proxy will never use the service account, it just... proxies the request.\n */\n proxy?:\n | boolean\n | Partial<\n ProxyPrimitiveOptions & {\n /**\n * If true, the remote service won't be available internally, only through the proxy.\n */\n noInternal: boolean;\n }\n >;\n\n /**\n * For communication between the server and the remote service with a security layer.\n * This will be used for internal communication and will not be exposed to the client.\n */\n serviceAccount?: ServiceAccountPrimitive;\n}\n\nexport class RemotePrimitive extends Primitive<RemotePrimitiveOptions> {\n public get name(): string {\n return this.options.name ?? this.config.propertyKey;\n }\n}\n\n$remote[KIND] = RemotePrimitive;\n","import { $env, $hook, $inject, Alepha, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { $retry } from \"alepha/retry\";\nimport type { ServiceAccountPrimitive } from \"alepha/security\";\nimport { ServerProxyProvider } from \"alepha/server/proxy\";\nimport { $remote, type RemotePrimitive } from \"../primitives/$remote.ts\";\nimport {\n type ApiLinksResponse,\n apiLinksResponseSchema,\n} from \"../schemas/apiLinksResponseSchema.ts\";\nimport { LinkProvider } from \"./LinkProvider.ts\";\n\nconst envSchema = t.object({\n SERVER_API_PREFIX: t.text({\n description: \"Prefix for all API routes (e.g. $action).\",\n default: \"/api\",\n }),\n});\n\nexport class RemotePrimitiveProvider {\n protected readonly env = $env(envSchema);\n protected readonly alepha = $inject(Alepha);\n protected readonly proxyProvider = $inject(ServerProxyProvider);\n protected readonly linkProvider = $inject(LinkProvider);\n protected readonly remotes: Array<ServerRemote> = [];\n protected readonly log = $logger();\n\n public getRemotes(): ServerRemote[] {\n return this.remotes;\n }\n\n public readonly configure = $hook({\n on: \"configure\",\n handler: async () => {\n const remotes = this.alepha.primitives($remote);\n for (const remote of remotes) {\n await this.registerRemote(remote);\n }\n },\n });\n\n public readonly start = $hook({\n on: \"start\",\n handler: async () => {\n for (const remote of this.remotes) {\n const token =\n typeof remote.serviceAccount?.token === \"function\"\n ? await remote.serviceAccount.token()\n : undefined;\n\n if (!remote.internal) {\n continue; // skip download links for remotes that are not internal\n }\n\n const { links } = await remote.links({ authorization: token });\n\n for (const link of links) {\n let path = link.path.replace(remote.prefix, \"\");\n if (link.service) {\n path = `/${link.service}${path}`;\n }\n\n this.linkProvider.registerLink({\n ...link,\n prefix: remote.prefix,\n path,\n method: link.method ?? \"GET\",\n host: remote.url,\n service: remote.name,\n });\n }\n\n this.log.info(`Remote '${remote.name}' OK`, {\n links: remote.links.length,\n prefix: remote.prefix,\n });\n }\n },\n });\n\n public async registerRemote(value: RemotePrimitive): Promise<void> {\n const options = value.options;\n const url = typeof options.url === \"string\" ? options.url : options.url();\n const linkPath = LinkProvider.path.apiLinks;\n const name = value.name;\n const proxy = typeof options.proxy === \"object\" ? options.proxy : {};\n\n const remote: ServerRemote = {\n url,\n name,\n prefix: \"/api\",\n serviceAccount: options.serviceAccount,\n proxy: !!options.proxy,\n internal: !proxy.noInternal,\n schema: async (opts) => {\n const { authorization, name } = opts;\n return await fetch(`${url}${linkPath}/${name}/schema`, {\n headers: new Headers(\n authorization\n ? {\n authorization,\n }\n : {},\n ),\n }).then((it) => it.json()); // TODO: use schema validation for response\n },\n links: async (opts) => {\n const { authorization } = opts;\n const remoteApi = await this.fetchLinks.run({\n service: name,\n url: `${url}${linkPath}`,\n authorization,\n });\n\n if (remoteApi.prefix != null) {\n remote.prefix = remoteApi.prefix; // monkey patch the prefix, not ideal but works\n }\n\n return remoteApi;\n },\n };\n\n this.remotes.push(remote);\n\n if (options.proxy) {\n this.proxyProvider.createProxy({\n path: `${this.env.SERVER_API_PREFIX}/${name}/*`,\n target: url,\n rewrite: (url) => {\n url.pathname = url.pathname.replace(\n `${this.env.SERVER_API_PREFIX}/${name}`,\n remote.prefix,\n );\n },\n ...proxy,\n });\n }\n }\n\n protected readonly fetchLinks = $retry({\n max: 10,\n backoff: {\n initial: 1000,\n },\n onError: (_, attempt, { service, url }) => {\n this.log.warn(`Failed to fetch links, retry (${attempt})...`, {\n service,\n url,\n });\n },\n handler: async (opts: FetchLinksOptions): Promise<ApiLinksResponse> => {\n const { url, authorization } = opts;\n const response = await fetch(url, {\n headers: new Headers(\n authorization\n ? {\n authorization,\n }\n : {},\n ),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch links from ${url}`);\n }\n\n return this.alepha.codec.decode(\n apiLinksResponseSchema,\n await response.json(),\n );\n },\n });\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface FetchLinksOptions {\n /**\n * Name of the remote service.\n */\n service: string;\n\n /**\n * URL to fetch links from.\n */\n url: string;\n\n /**\n * Authorization header containing access token.\n */\n authorization?: string;\n}\n\nexport interface ServerRemote {\n /**\n * URL of the remote service.\n */\n url: string;\n\n /**\n * Name of the remote service.\n */\n name: string;\n\n /**\n * Expose links as endpoint. It's not only internal.\n */\n proxy: boolean;\n\n /**\n * It's only used inside the application.\n */\n internal: boolean;\n\n /**\n * Links fetcher.\n */\n links: (args: { authorization?: string }) => Promise<ApiLinksResponse>;\n\n /**\n * Fetches schema for the remote service.\n */\n schema: (args: { name: string; authorization?: string }) => Promise<any>;\n\n /**\n * Force a default access token provider when not provided.\n */\n serviceAccount?: ServiceAccountPrimitive;\n\n /**\n * Prefix for the remote service links.\n */\n prefix: string;\n}\n","import { $env, $hook, $inject, Alepha, t } from \"alepha\";\nimport {\n type Permission,\n SecurityProvider,\n type UserAccountToken,\n} from \"alepha/security\";\nimport {\n $action,\n $route,\n type ClientRequestEntry,\n type ClientRequestOptions,\n type RequestConfigSchema,\n ServerTimingProvider,\n} from \"alepha/server\";\nimport {\n type ApiLink,\n type ApiLinksResponse,\n apiLinksResponseSchema,\n} from \"../schemas/apiLinksResponseSchema.ts\";\nimport { LinkProvider } from \"./LinkProvider.ts\";\nimport { RemotePrimitiveProvider } from \"./RemotePrimitiveProvider.ts\";\n\nconst envSchema = t.object({\n SERVER_API_PREFIX: t.text({\n description: \"Prefix for all API routes (e.g. $action).\",\n default: \"/api\",\n }),\n});\n\nexport class ServerLinksProvider {\n protected readonly env = $env(envSchema);\n protected readonly alepha = $inject(Alepha);\n protected readonly linkProvider = $inject(LinkProvider);\n protected readonly remoteProvider = $inject(RemotePrimitiveProvider);\n protected readonly serverTimingProvider = $inject(ServerTimingProvider);\n\n public get prefix() {\n return this.env.SERVER_API_PREFIX;\n }\n\n public readonly onRoute = $hook({\n on: \"configure\",\n handler: () => {\n // convert all $action to local links\n for (const action of this.alepha.primitives($action)) {\n this.linkProvider.registerLink({\n name: action.name,\n group: action.group,\n schema: action.options.schema,\n requestBodyType: action.getBodyContentType(),\n secured: action.options.secure,\n method: action.method === \"GET\" ? undefined : action.method,\n prefix: action.prefix,\n path: action.path,\n // by local, we mean that it can be called directly via the handler\n handler: (\n config: ClientRequestEntry<RequestConfigSchema>,\n options: ClientRequestOptions = {},\n ) => action.run(config, options),\n });\n }\n },\n });\n\n /**\n * First API - Get all API links for the user.\n *\n * This is based on the user's permissions.\n */\n public readonly links = $route({\n path: LinkProvider.path.apiLinks,\n schema: {\n response: apiLinksResponseSchema,\n },\n handler: ({ user, headers }) => {\n return this.getUserApiLinks({\n user,\n authorization: headers.authorization,\n });\n },\n });\n\n /**\n * Retrieves API links for the user based on their permissions.\n * Will check on local links and remote links.\n */\n public async getUserApiLinks(\n options: GetApiLinksOptions,\n ): Promise<ApiLinksResponse> {\n const { user } = options;\n let permissions: Permission[] | undefined;\n let permissionMap: Map<string, Permission> | undefined;\n const hasSecurity = this.alepha.has(SecurityProvider);\n if (hasSecurity && user) {\n permissions = this.alepha.inject(SecurityProvider).getPermissions(user);\n permissionMap = new Map(\n permissions.map((it) => [`${it.group}:${it.name}`, it]),\n );\n }\n\n const userLinks: ApiLink[] = [];\n\n // bonus: add permissions not related to $action\n for (const permission of permissions ?? []) {\n if (\n !permission.path &&\n !permission.method &&\n permission.name &&\n permission.group\n ) {\n userLinks.push({\n path: \"\", // this is a placeholder for links without specific path\n name: permission.name,\n group: permission.group,\n });\n }\n }\n\n // add local links\n for (const link of this.linkProvider.getServerLinks()) {\n // SKIP REMOTE LINKS, remote links are handled separately for security\n if (link.host) continue;\n\n if (hasSecurity && link.secured) {\n // skip secured links if user is not provided\n if (!user) {\n continue;\n }\n\n if (typeof link.secured === \"object\" && link.secured.realm) {\n // realm check\n if (user.realm !== link.secured.realm) {\n continue;\n }\n } else if (permissionMap) {\n // small permissions check, can be optimized later ... :')\n\n if (!permissionMap.has(`${link.group}:${link.name}`)) {\n continue;\n }\n }\n }\n\n userLinks.push({\n name: link.name,\n group: link.group,\n requestBodyType: link.requestBodyType,\n method: link.method,\n path: link.path,\n rawSchema: link.rawSchema,\n });\n }\n\n this.serverTimingProvider.beginTiming(\"fetchRemoteLinks\");\n // this does not scale well, but it's working for now\n // TODO: remote links can be cached by user.roles\n const promises = this.remoteProvider\n .getRemotes()\n .filter((it) => it.proxy) // add only \"proxy\" remotes\n .map(async (remote) => {\n const { links, prefix } = await remote.links(options);\n return links.map((link) => {\n let path = link.path.replace(prefix ?? \"/api\", \"\");\n if (link.service) {\n path = `/${link.service}${path}`;\n }\n\n return {\n ...link,\n path,\n proxy: true,\n service: remote.name,\n };\n });\n });\n\n userLinks.push(...(await Promise.all(promises)).flat());\n this.serverTimingProvider.endTiming(\"fetchRemoteLinks\");\n\n return {\n prefix: this.env.SERVER_API_PREFIX,\n links: userLinks,\n };\n }\n}\n\nexport interface GetApiLinksOptions {\n user?: UserAccountToken;\n authorization?: string;\n}\n","import \"alepha/security\";\nimport { $module } from \"alepha\";\nimport { AlephaServer } from \"alepha/server\";\nimport { apiLinksAtom } from \"./atoms/apiLinksAtom.ts\";\nimport { $client } from \"./primitives/$client.ts\";\nimport { $remote } from \"./primitives/$remote.ts\";\nimport { LinkProvider } from \"./providers/LinkProvider.ts\";\nimport { RemotePrimitiveProvider } from \"./providers/RemotePrimitiveProvider.ts\";\nimport { ServerLinksProvider } from \"./providers/ServerLinksProvider.ts\";\nimport type { ApiLinksResponse } from \"./schemas/apiLinksResponseSchema.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./primitives/$client.ts\";\nexport * from \"./primitives/$remote.ts\";\nexport * from \"./providers/LinkProvider.ts\";\nexport * from \"./providers/RemotePrimitiveProvider.ts\";\nexport * from \"./providers/ServerLinksProvider.ts\";\nexport * from \"./schemas/apiLinksResponseSchema.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface State {\n /**\n * API links attached to the server request state.\n *\n * @see {@link ApiLinksResponse}\n * @internal\n */\n \"alepha.server.request.apiLinks\"?: ApiLinksResponse;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * | type | quality | stability |\n * |------|---------|-----------|\n * | backend | standard | stable |\n *\n * Type-safe API client with request deduplication.\n *\n * **Features:**\n * - Virtual HTTP client for type-safe API calls\n * - Remote action definitions\n * - Type inference from action schemas\n * - Request deduplication\n * - Automatic error handling\n *\n * @module alepha.server.links\n */\nexport const AlephaServerLinks = $module({\n name: \"alepha.server.links\",\n atoms: [apiLinksAtom],\n primitives: [$remote, $client],\n services: [\n AlephaServer,\n ServerLinksProvider,\n RemotePrimitiveProvider,\n LinkProvider,\n ],\n});\n"],"mappings":"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"}
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -275,6 +275,7 @@ interface GenerateCloudflareOptions {
|
|
|
275
275
|
* Additional Wrangler configuration options to merge into wrangler.jsonc.
|
|
276
276
|
*/
|
|
277
277
|
config?: WranglerConfig;
|
|
278
|
+
alepha: Alepha;
|
|
278
279
|
}
|
|
279
280
|
interface WranglerConfig {
|
|
280
281
|
[key: string]: any;
|
|
@@ -286,7 +287,7 @@ interface WranglerConfig {
|
|
|
286
287
|
* - wrangler.jsonc with worker configuration
|
|
287
288
|
* - worker.js entry point for Cloudflare Workers
|
|
288
289
|
*/
|
|
289
|
-
declare function generateCloudflare(opts
|
|
290
|
+
declare function generateCloudflare(opts: GenerateCloudflareOptions): Promise<void>;
|
|
290
291
|
//#endregion
|
|
291
292
|
//#region ../../src/vite/tasks/generateDocker.d.ts
|
|
292
293
|
interface GenerateDockerOptions {
|
package/dist/vite/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/vite/helpers/createBufferedLogger.ts","../../src/vite/helpers/importVite.ts","../../src/vite/helpers/importViteReact.ts","../../src/vite/plugins/viteAlephaSsrPreload.ts","../../src/vite/plugins/viteCompress.ts","../../src/vite/tasks/buildClient.ts","../../src/vite/tasks/buildServer.ts","../../src/vite/tasks/copyAssets.ts","../../src/vite/tasks/generateCloudflare.ts","../../src/vite/tasks/generateDocker.ts","../../src/vite/tasks/generateExternals.ts","../../src/vite/tasks/generateSitemap.ts","../../src/vite/tasks/generateVercel.ts","../../src/vite/tasks/prerenderPages.ts","../../src/vite/index.ts"],"mappings":";;;;;;UAEU,gBAAA;EACR,KAAA;EACA,GAAA;EACA,SAAA,EAAW,IAAA;AAAA;AAAA,UAGI,cAAA,SAAuB,MAAA;EANd;;;;EAWxB,KAAA;EARA;;;EAaA,UAAA,IAAc,gBAAA;EAVC;;;EAef,KAAA;AAAA;;;;;;;AAkBF;;;;;;;;ACtCA;iBDsCgB,oBAAA,CAAA,GAAwB,cAAA;;;cCtC3B,UAAA,QAAuB,OAAA,QAAe,IAAA;;;cCDtC,eAAA,QAA4B,OAAA;;;;;;;UCOxB,eAAA;EAAA,CACd,GAAA;AAAA;;;;;;;;;AHFH;;;;;;;;;;;AAiCA;;;;;;;;ACtCA;;;;;;;;ACDA;;;iBCiDgB,oBAAA,CAAA,GAAwB,MAAA;;;UCrCvB,mBAAA;;;;AJdkB;;EIoBjC,QAAA;EJfe;;;;;;EIuBf,MAAA,aAAmB,aAAA;EJpBJ;;;;;;EI4Bf,IAAA,aAAiB,WAAA;EJlBH;;;;AAuBhB;;EIGE,MAAA,GAAS,MAAA,KAAW,QAAA;AAAA;AAAA,iBAGN,YAAA,CAAa,OAAA,GAAS,mBAAA,GAA2B,MAAA;AAAA,iBA6C3C,YAAA,CACpB,OAAA,EAAS,mBAAA,cACT,QAAA,WAAgB,OAAA;;;UCnFD,kBAAA;;;;EAIf,IAAA;ELbQ;;;;;EKoBR,WAAA,GAAc,mBAAA;ELjBd;;;;AAGF;EKqBE,SAAA;;;;EAKA,OAAA;IACE,QAAA;EAAA;ELZF;;;EKkBA,KAAA;ELAkC;;;;;EKOlC,MAAA;AAAA;AJ7CF;;;;;;AAAA,iBIsDsB,WAAA,CAAY,IAAA,EAAM,kBAAA,GAAqB,OAAA;;;UC7C5C,kBAAA;;;;EAIf,KAAA;ENdQ;;;EMmBR,OAAA;ENlBA;;;;EMwBA,SAAA;ENtBe;AAGjB;;EMwBE,KAAA;ENxB4C;;;;;EM+B5C,MAAA;ENhBK;;AAkBP;EMGE,UAAA;;;;EAKA,MAAA,EAAQ,MAAA;AAAA;AAAA,UAGO,iBAAA;ELjDJ;;;EKqDX,SAAA;ELrDqD;;;;EK2DrD,QAAA;IACE,IAAA;IACA,MAAA,GAAS,MAAA;IACT,OAAA,GAAU,MAAA;EAAA;AAAA;;;AHxDd;;;;;iBGmEsB,WAAA,CACpB,IAAA,EAAM,kBAAA,GACL,OAAA,CAAQ,iBAAA;;;UCzEM,iBAAA;EACf,MAAA,EAAQ,MAAA;;;;EAIR,KAAA;EPRwB;;;EOaxB,OAAA;EPXA;;;EOgBA,IAAA;EPfe;AAGjB;;EOiBE,GAAA,IAAO,IAAA;IACL,IAAA;IACA,OAAA,QAAe,OAAA;EAAA,MACX,OAAA;AAAA;;;;;APaR;;;;;iBODsB,UAAA,CAAW,IAAA,EAAM,iBAAA,GAAoB,OAAA;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/vite/helpers/createBufferedLogger.ts","../../src/vite/helpers/importVite.ts","../../src/vite/helpers/importViteReact.ts","../../src/vite/plugins/viteAlephaSsrPreload.ts","../../src/vite/plugins/viteCompress.ts","../../src/vite/tasks/buildClient.ts","../../src/vite/tasks/buildServer.ts","../../src/vite/tasks/copyAssets.ts","../../src/vite/tasks/generateCloudflare.ts","../../src/vite/tasks/generateDocker.ts","../../src/vite/tasks/generateExternals.ts","../../src/vite/tasks/generateSitemap.ts","../../src/vite/tasks/generateVercel.ts","../../src/vite/tasks/prerenderPages.ts","../../src/vite/index.ts"],"mappings":"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"}
|
package/dist/vite/index.js
CHANGED
|
@@ -538,11 +538,16 @@ const WARNING_COMMENT$1 = "// This file was automatically generated. DO NOT MODI
|
|
|
538
538
|
* - wrangler.jsonc with worker configuration
|
|
539
539
|
* - worker.js entry point for Cloudflare Workers
|
|
540
540
|
*/
|
|
541
|
-
async function generateCloudflare(opts
|
|
541
|
+
async function generateCloudflare(opts) {
|
|
542
542
|
const distDir = opts.distDir ?? "dist";
|
|
543
543
|
const root = process.cwd();
|
|
544
544
|
const name = basename(root);
|
|
545
545
|
const hasAssets = await access(join(root, distDir, "public")).then(() => true).catch(() => false);
|
|
546
|
+
let workerdCronProvider;
|
|
547
|
+
try {
|
|
548
|
+
workerdCronProvider = opts.alepha.inject("CronProvider");
|
|
549
|
+
} catch {}
|
|
550
|
+
const crons = workerdCronProvider?.getCronJobs();
|
|
546
551
|
const wrangler = {
|
|
547
552
|
name,
|
|
548
553
|
main: "./main.cloudflare.js",
|
|
@@ -559,6 +564,11 @@ async function generateCloudflare(opts = {}) {
|
|
|
559
564
|
directory: "./public",
|
|
560
565
|
binding: "ASSETS"
|
|
561
566
|
};
|
|
567
|
+
if (crons && crons.length > 0) {
|
|
568
|
+
const cronExpressions = [...new Set(crons.map((c) => c.expression))];
|
|
569
|
+
wrangler.triggers ??= {};
|
|
570
|
+
wrangler.triggers.crons = cronExpressions;
|
|
571
|
+
}
|
|
562
572
|
const url = process.env.DATABASE_URL;
|
|
563
573
|
if (url?.startsWith("d1:")) {
|
|
564
574
|
const [name, id] = url.replace("d1://", "").replace("d1:", "").split(":");
|
|
@@ -590,7 +600,7 @@ export default {
|
|
|
590
600
|
try {
|
|
591
601
|
await __alepha.start();
|
|
592
602
|
} catch (err) {
|
|
593
|
-
console.error(err);
|
|
603
|
+
console.error("Failed to start Alepha for fetch event", err);
|
|
594
604
|
return new Response("Internal Server Error", { status: 500 });
|
|
595
605
|
}
|
|
596
606
|
|
|
@@ -598,6 +608,22 @@ export default {
|
|
|
598
608
|
|
|
599
609
|
return ctx.res;
|
|
600
610
|
},
|
|
611
|
+
|
|
612
|
+
scheduled: async (event, env, ctx) => {
|
|
613
|
+
__alepha.set("cloudflare.env", env);
|
|
614
|
+
|
|
615
|
+
try {
|
|
616
|
+
await __alepha.start();
|
|
617
|
+
} catch (err) {
|
|
618
|
+
console.error("Failed to start Alepha for scheduled event", err);
|
|
619
|
+
throw err;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
await __alepha.events.emit("cloudflare:scheduled", {
|
|
623
|
+
cron: event.cron,
|
|
624
|
+
scheduledTime: event.scheduledTime,
|
|
625
|
+
});
|
|
626
|
+
},
|
|
601
627
|
};
|
|
602
628
|
`.trim();
|
|
603
629
|
await writeFile(join(root, distDir, "main.cloudflare.js"), `${WARNING_COMMENT$1}\n${workerCode}`.trim());
|