@wabot-dev/framework 0.9.80 → 2.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/skills.mjs +151 -0
- package/bin/wabot-skills.mjs +120 -0
- package/dist/build/build.js +1031 -8
- package/dist/src/addon/chat-bot/in-memory/InMemoryChatMemory.js +1 -3
- package/dist/src/addon/chat-bot/xai/XAIChatAdapter.js +180 -0
- package/dist/src/addon/chat-controller/cmd/cmdChannelSocketPath.js +1 -5
- package/dist/src/addon/chat-controller/hubspot/@hubspot.js +28 -0
- package/dist/src/addon/chat-controller/hubspot/HubSpotChannel.js +81 -0
- package/dist/src/addon/chat-controller/hubspot/HubSpotChannelConfig.js +20 -0
- package/dist/src/addon/chat-controller/hubspot/HubSpotReceiver.js +42 -0
- package/dist/src/addon/chat-controller/hubspot/HubSpotSender.js +118 -0
- package/dist/src/addon/chat-controller/hubspot/HubSpotWebhookController.js +122 -0
- package/dist/src/addon/chat-controller/hubspot/downloadHubSpotAttachments.js +45 -0
- package/dist/src/addon/chat-controller/hubspot/hubspotChannelName.js +3 -0
- package/dist/src/addon/chat-controller/hubspot/verifyHubSpotSignatureV3.js +28 -0
- package/dist/src/addon/chat-controller/{telegram/markdownToTelegramHtml.js → markdown/markdownToChatHtml.js} +5 -8
- package/dist/src/addon/chat-controller/slack/@slack.js +22 -0
- package/dist/src/addon/chat-controller/slack/SlackChannel.js +187 -0
- package/dist/src/addon/chat-controller/slack/SlackChannelConfig.js +12 -0
- package/dist/src/addon/chat-controller/slack/markdownToSlackMrkdwn.js +38 -0
- package/dist/src/addon/chat-controller/slack/slackChannelName.js +3 -0
- package/dist/src/addon/chat-controller/telegram/TelegramChannel.js +2 -2
- package/dist/src/addon/ui/preact/PreactRenderer.js +86 -0
- package/dist/src/addon/ui/preact/outlet.js +22 -0
- package/dist/src/addon/ui/preact/preactClientRuntime.js +67 -0
- package/dist/src/core/repository/CrudRepository.js +7 -7
- package/dist/src/feature/async/computeDedupKey.js +1 -1
- package/dist/src/feature/pg/@pgExtension.js +2 -4
- package/dist/src/feature/project-runner/ProjectRunner.js +62 -10
- package/dist/src/feature/project-runner/scanner.js +1 -1
- package/dist/src/feature/repository/@memExtension.js +1 -2
- package/dist/src/feature/ui-controller/actions.js +35 -0
- package/dist/src/feature/ui-controller/bundler/UiBundler.js +191 -0
- package/dist/src/feature/ui-controller/bundler/devMiddleware.js +41 -0
- package/dist/src/feature/ui-controller/bundler/index.js +4 -0
- package/dist/src/feature/ui-controller/bundler/manifest.js +34 -0
- package/dist/src/feature/ui-controller/bundler/navRuntime.js +236 -0
- package/dist/src/feature/ui-controller/bundler/pageAssets.js +30 -0
- package/dist/src/feature/ui-controller/document/escape.js +17 -0
- package/dist/src/feature/ui-controller/document/helpers.js +13 -0
- package/dist/src/feature/ui-controller/document/renderDocument.js +43 -0
- package/dist/src/feature/ui-controller/island/IslandRegistry.js +68 -0
- package/dist/src/feature/ui-controller/island/island.js +40 -0
- package/dist/src/feature/ui-controller/island/serialize.js +35 -0
- package/dist/src/feature/ui-controller/metadata/@action.js +18 -0
- package/dist/src/feature/ui-controller/metadata/@uiController.js +19 -0
- package/dist/src/feature/ui-controller/metadata/@uiMiddleware.js +20 -0
- package/dist/src/feature/ui-controller/metadata/@view.js +18 -0
- package/dist/src/feature/ui-controller/metadata/UiControllerMetadataStore.js +107 -0
- package/dist/src/feature/ui-controller/renderer/UiRendererRegistry.js +42 -0
- package/dist/src/feature/ui-controller/runUiControllers.js +285 -0
- package/dist/src/index.d.ts +632 -3
- package/dist/src/index.js +30 -1
- package/dist/src/testing/index.d.ts +43 -1
- package/dist/src/testing/index.js +1 -0
- package/dist/src/testing/uiHarness.js +102 -0
- package/dist/src/ui/client.js +6 -0
- package/dist/src/ui/index.d.ts +427 -0
- package/dist/src/ui/index.js +29 -0
- package/dist/src/ui/jsx-dev-runtime.d.ts +1 -0
- package/dist/src/ui/jsx-dev-runtime.js +1 -0
- package/dist/src/ui/jsx-runtime.d.ts +1 -0
- package/dist/src/ui/jsx-runtime.js +1 -0
- package/package.json +33 -13
- package/skills/wabot-async/SKILL.md +143 -0
- package/skills/wabot-auth/SKILL.md +153 -0
- package/skills/wabot-chat/SKILL.md +140 -0
- package/skills/wabot-di-config/SKILL.md +117 -0
- package/skills/wabot-framework/SKILL.md +81 -0
- package/skills/wabot-framework/references/quickstart.md +85 -0
- package/skills/wabot-mindset/SKILL.md +159 -0
- package/skills/wabot-ops/SKILL.md +151 -0
- package/skills/wabot-persistence/SKILL.md +159 -0
- package/skills/wabot-rest-socket/SKILL.md +167 -0
- package/skills/wabot-testing/SKILL.md +214 -0
- package/skills/wabot-ui/SKILL.md +201 -0
- package/skills/wabot-validation/SKILL.md +108 -0
package/dist/src/index.js
CHANGED
|
@@ -130,6 +130,20 @@ export { socketController } from './feature/socket-controller/metadata/@socketCo
|
|
|
130
130
|
export { onSocketEvent } from './feature/socket-controller/metadata/@onSocketEvent.js';
|
|
131
131
|
export { SocketControllerMetadataStore } from './feature/socket-controller/metadata/SocketControllerMetadataStore.js';
|
|
132
132
|
export { runSocketControllers } from './feature/socket-controller/runSocketControllers.js';
|
|
133
|
+
export { uiController } from './feature/ui-controller/metadata/@uiController.js';
|
|
134
|
+
export { view } from './feature/ui-controller/metadata/@view.js';
|
|
135
|
+
export { action } from './feature/ui-controller/metadata/@action.js';
|
|
136
|
+
export { uiMiddleware } from './feature/ui-controller/metadata/@uiMiddleware.js';
|
|
137
|
+
export { UiControllerMetadataStore } from './feature/ui-controller/metadata/UiControllerMetadataStore.js';
|
|
138
|
+
export { UiRendererRegistry } from './feature/ui-controller/renderer/UiRendererRegistry.js';
|
|
139
|
+
export { ISLAND_MARKER, getIslandMeta, isIsland, island, setIslandId } from './feature/ui-controller/island/island.js';
|
|
140
|
+
export { deserializeProps, serializeProps } from './feature/ui-controller/island/serialize.js';
|
|
141
|
+
export { ISLAND_FILE_PATTERN, IslandRegistry, isIslandFile, toIslandId } from './feature/ui-controller/island/IslandRegistry.js';
|
|
142
|
+
export { renderDocument } from './feature/ui-controller/document/renderDocument.js';
|
|
143
|
+
export { REDIRECT_MARKER, isRedirect, redirect } from './feature/ui-controller/document/helpers.js';
|
|
144
|
+
export { escapeAttr, escapeHtml } from './feature/ui-controller/document/escape.js';
|
|
145
|
+
export { actionUrl, callAction } from './feature/ui-controller/actions.js';
|
|
146
|
+
export { registerUiControllers, runUiControllers } from './feature/ui-controller/runUiControllers.js';
|
|
133
147
|
export { PgCronJobRepository } from './addon/async/pg/PgCronJobRepository.js';
|
|
134
148
|
export { PgJobRepository } from './addon/async/pg/PgJobRepository.js';
|
|
135
149
|
export { PgTransactionAdapter } from './addon/async/pg/PgTransactionAdapter.js';
|
|
@@ -165,6 +179,7 @@ export { PgChatMemory } from './addon/chat-bot/pg/PgChatMemory.js';
|
|
|
165
179
|
export { InMemoryChatMemory } from './addon/chat-bot/in-memory/InMemoryChatMemory.js';
|
|
166
180
|
export { InMemoryChatRepository } from './addon/chat-bot/in-memory/InMemoryChatRepository.js';
|
|
167
181
|
export { WabotChatAdapter } from './addon/chat-bot/wabot/WabotChatAdapter.js';
|
|
182
|
+
export { XAIChatAdapter } from './addon/chat-bot/xai/XAIChatAdapter.js';
|
|
168
183
|
export { cmd } from './addon/chat-controller/cmd/@cmd.js';
|
|
169
184
|
export { CmdChannel, readJsonFromFile, writeJsonToFile } from './addon/chat-controller/cmd/CmdChannel.js';
|
|
170
185
|
export { CmdChannelConfig } from './addon/chat-controller/cmd/CmdChannelConfig.js';
|
|
@@ -172,6 +187,21 @@ export { CmdChannelServer } from './addon/chat-controller/cmd/CmdChannelServer.j
|
|
|
172
187
|
export { cmdChannelName } from './addon/chat-controller/cmd/cmdChannelName.js';
|
|
173
188
|
export { cmdChannelSocketPath } from './addon/chat-controller/cmd/cmdChannelSocketPath.js';
|
|
174
189
|
export { runCmdClient } from './addon/chat-controller/cmd/runCmdClient.js';
|
|
190
|
+
export { hubspotChannelName } from './addon/chat-controller/hubspot/hubspotChannelName.js';
|
|
191
|
+
export { HubSpotChannelConfig } from './addon/chat-controller/hubspot/HubSpotChannelConfig.js';
|
|
192
|
+
export { verifyHubSpotSignatureV3 } from './addon/chat-controller/hubspot/verifyHubSpotSignatureV3.js';
|
|
193
|
+
export { downloadHubSpotAttachments } from './addon/chat-controller/hubspot/downloadHubSpotAttachments.js';
|
|
194
|
+
export { HubSpotSender } from './addon/chat-controller/hubspot/HubSpotSender.js';
|
|
195
|
+
export { HubSpotWebhookController } from './addon/chat-controller/hubspot/HubSpotWebhookController.js';
|
|
196
|
+
export { HubSpotReceiver } from './addon/chat-controller/hubspot/HubSpotReceiver.js';
|
|
197
|
+
export { HubSpotChannel } from './addon/chat-controller/hubspot/HubSpotChannel.js';
|
|
198
|
+
export { markdownToChatHtml as markdownToHubSpotHtml, markdownToChatHtml as markdownToTelegramHtml } from './addon/chat-controller/markdown/markdownToChatHtml.js';
|
|
199
|
+
export { hubspot } from './addon/chat-controller/hubspot/@hubspot.js';
|
|
200
|
+
export { slack } from './addon/chat-controller/slack/@slack.js';
|
|
201
|
+
export { SlackChannelConfig } from './addon/chat-controller/slack/SlackChannelConfig.js';
|
|
202
|
+
export { SlackChannel } from './addon/chat-controller/slack/SlackChannel.js';
|
|
203
|
+
export { slackChannelName } from './addon/chat-controller/slack/slackChannelName.js';
|
|
204
|
+
export { markdownToSlackMrkdwn } from './addon/chat-controller/slack/markdownToSlackMrkdwn.js';
|
|
175
205
|
export { socket } from './addon/chat-controller/socket/@socket.js';
|
|
176
206
|
export { SocketChannel, SocketChannelMessageFile, SocketChannelReceivedMessage } from './addon/chat-controller/socket/SocketChannel.js';
|
|
177
207
|
export { SocketChannelConfig } from './addon/chat-controller/socket/SocketChannelConfig.js';
|
|
@@ -180,7 +210,6 @@ export { telegram } from './addon/chat-controller/telegram/@telegram.js';
|
|
|
180
210
|
export { TelegramChannelConfig } from './addon/chat-controller/telegram/TelegramChannelConfig.js';
|
|
181
211
|
export { TelegramChannel } from './addon/chat-controller/telegram/TelegramChannel.js';
|
|
182
212
|
export { telegramChannelName } from './addon/chat-controller/telegram/telegramChannelName.js';
|
|
183
|
-
export { markdownToTelegramHtml } from './addon/chat-controller/telegram/markdownToTelegramHtml.js';
|
|
184
213
|
export { WhatsAppReceiverByCloudApi } from './addon/chat-controller/whatsapp/cloud-api/WhatsAppReceiverByCloudApi.js';
|
|
185
214
|
export { WhatsAppApiSender } from './addon/chat-controller/whatsapp/cloud-api/WhatsAppApiSender.js';
|
|
186
215
|
export { kapso } from './addon/chat-controller/whatsapp/kapso/@kapso.js';
|
|
@@ -701,6 +701,48 @@ declare class RestHarness {
|
|
|
701
701
|
}
|
|
702
702
|
declare function createRestHarness(options: IRestHarnessOptions): Promise<RestHarness>;
|
|
703
703
|
|
|
704
|
+
interface IUiHarnessOptions {
|
|
705
|
+
controllers: IConstructor<any>[];
|
|
706
|
+
/** Extra DI registrations visible to middlewares and controllers: [token, instance]. */
|
|
707
|
+
register?: [any, any][];
|
|
708
|
+
}
|
|
709
|
+
interface IUiRequestOptions {
|
|
710
|
+
body?: unknown;
|
|
711
|
+
headers?: Record<string, string>;
|
|
712
|
+
query?: Record<string, string>;
|
|
713
|
+
/** Follow redirects ("follow", default) or capture them ("manual"). */
|
|
714
|
+
redirect?: 'follow' | 'manual';
|
|
715
|
+
}
|
|
716
|
+
interface IUiResponse {
|
|
717
|
+
status: number;
|
|
718
|
+
/** Raw response body. */
|
|
719
|
+
text: string;
|
|
720
|
+
headers: Headers;
|
|
721
|
+
/** Parse the body as JSON (for @action responses). */
|
|
722
|
+
json(): any;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Mounts @uiController classes on a private HTTP server (ephemeral port) and
|
|
726
|
+
* exercises the real pipeline: middlewares/guards, validation, SSR and actions.
|
|
727
|
+
* Islands render as static SSR HTML (no client bundling needed for tests).
|
|
728
|
+
*/
|
|
729
|
+
declare class UiHarness {
|
|
730
|
+
readonly container: DependencyContainer;
|
|
731
|
+
private server;
|
|
732
|
+
private baseUrl;
|
|
733
|
+
private constructor();
|
|
734
|
+
static create(options: IUiHarnessOptions): Promise<UiHarness>;
|
|
735
|
+
private listen;
|
|
736
|
+
get url(): string;
|
|
737
|
+
/** GET a view; returns the rendered HTML document. */
|
|
738
|
+
get(path: string, options?: IUiRequestOptions): Promise<IUiResponse>;
|
|
739
|
+
/** POST to an @action route (e.g. "/my/ui/_action/addTodo"). */
|
|
740
|
+
action(path: string, body?: unknown, options?: IUiRequestOptions): Promise<IUiResponse>;
|
|
741
|
+
request(method: string, path: string, options?: IUiRequestOptions): Promise<IUiResponse>;
|
|
742
|
+
close(): Promise<void>;
|
|
743
|
+
}
|
|
744
|
+
declare function createUiHarness(options: IUiHarnessOptions): Promise<UiHarness>;
|
|
745
|
+
|
|
704
746
|
interface ICronHandler {
|
|
705
747
|
handle(): void | Promise<void>;
|
|
706
748
|
handleError?(e: any): void | Promise<void>;
|
|
@@ -773,4 +815,4 @@ interface ICronValidationOptions {
|
|
|
773
815
|
/** Check that a sequence of dates matches consecutive firings of a cron expression. */
|
|
774
816
|
declare function isValidCronSequence(cronExpression: string, dates: Date[], options?: ICronValidationOptions): boolean;
|
|
775
817
|
|
|
776
|
-
export { AsyncHarness, ChatBotHarness, ChatControllerHarness, type IAsyncHarnessOptions, type IChatAdapterConformanceCase, type IChatAdapterConformanceReq, type IChatBotHarnessOptions, type IChatBotTurn, type IChatControllerHarnessOptions, type ICronValidationOptions, type IEntityFixtureOptions, type IFileFixtureOptions, type ILlmJudgeEvaluateReq, type ILlmJudgeOptions, type ILlmJudgeVerdict, type IMockChatAdapterOptions, type IMockChatAdapterResponse, type IRestHarnessOptions, type IRestRequestOptions, type IRestResponse, type ITestJwtOptions, type IValidationFixtureResult, type IValidationIssue, LlmJudge, MockChatAdapter, RestHarness, TestApiKeyRepository, TestChatMemory, TestChatRepository, TestJwt, assertInvalid, assertValid, botItem, chatAdapterConformanceCases, createAsyncHarness, createChatBotHarness, createChatControllerHarness, createRestHarness, documentMessage, entityFixture, humanItem, humanMessage, imageMessage, isValidCronSequence, renderTranscript, setupTestJwt, testImageBase64Url, testPdfBase64Url, useMemoryRepositories, validateFixture, wait, waitUntil };
|
|
818
|
+
export { AsyncHarness, ChatBotHarness, ChatControllerHarness, type IAsyncHarnessOptions, type IChatAdapterConformanceCase, type IChatAdapterConformanceReq, type IChatBotHarnessOptions, type IChatBotTurn, type IChatControllerHarnessOptions, type ICronValidationOptions, type IEntityFixtureOptions, type IFileFixtureOptions, type ILlmJudgeEvaluateReq, type ILlmJudgeOptions, type ILlmJudgeVerdict, type IMockChatAdapterOptions, type IMockChatAdapterResponse, type IRestHarnessOptions, type IRestRequestOptions, type IRestResponse, type ITestJwtOptions, type IUiHarnessOptions, type IUiRequestOptions, type IUiResponse, type IValidationFixtureResult, type IValidationIssue, LlmJudge, MockChatAdapter, RestHarness, TestApiKeyRepository, TestChatMemory, TestChatRepository, TestJwt, UiHarness, assertInvalid, assertValid, botItem, chatAdapterConformanceCases, createAsyncHarness, createChatBotHarness, createChatControllerHarness, createRestHarness, createUiHarness, documentMessage, entityFixture, humanItem, humanMessage, imageMessage, isValidCronSequence, renderTranscript, setupTestJwt, testImageBase64Url, testPdfBase64Url, useMemoryRepositories, validateFixture, wait, waitUntil };
|
|
@@ -6,6 +6,7 @@ export { LlmJudge, renderTranscript } from './LlmJudge.js';
|
|
|
6
6
|
export { botItem, documentMessage, humanItem, humanMessage, imageMessage, testImageBase64Url, testPdfBase64Url } from './fixtures.js';
|
|
7
7
|
export { chatAdapterConformanceCases } from './conformance/chatAdapterConformanceCases.js';
|
|
8
8
|
export { RestHarness, createRestHarness } from './restHarness.js';
|
|
9
|
+
export { UiHarness, createUiHarness } from './uiHarness.js';
|
|
9
10
|
export { AsyncHarness, createAsyncHarness } from './asyncHarness.js';
|
|
10
11
|
export { entityFixture, useMemoryRepositories } from './repositories.js';
|
|
11
12
|
export { TestApiKeyRepository, TestJwt, setupTestJwt } from './auth.js';
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { container } from '../core/injection/index.js';
|
|
2
|
+
import { ExpressProvider } from '../feature/express/ExpressProvider.js';
|
|
3
|
+
import { HttpServerProvider } from '../feature/http/HttpServerProvider.js';
|
|
4
|
+
import '../feature/ui-controller/metadata/UiControllerMetadataStore.js';
|
|
5
|
+
import { UiRendererRegistry } from '../feature/ui-controller/renderer/UiRendererRegistry.js';
|
|
6
|
+
import '../feature/ui-controller/island/IslandRegistry.js';
|
|
7
|
+
import { registerUiControllers } from '../feature/ui-controller/runUiControllers.js';
|
|
8
|
+
import { PreactRenderer } from '../addon/ui/preact/PreactRenderer.js';
|
|
9
|
+
import '../addon/ui/preact/outlet.js';
|
|
10
|
+
import { Container } from '../core/injection/Container.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Mounts @uiController classes on a private HTTP server (ephemeral port) and
|
|
14
|
+
* exercises the real pipeline: middlewares/guards, validation, SSR and actions.
|
|
15
|
+
* Islands render as static SSR HTML (no client bundling needed for tests).
|
|
16
|
+
*/
|
|
17
|
+
class UiHarness {
|
|
18
|
+
container;
|
|
19
|
+
server;
|
|
20
|
+
baseUrl = '';
|
|
21
|
+
constructor(options) {
|
|
22
|
+
const child = container.createChildContainer();
|
|
23
|
+
child.register(Container, { useValue: child });
|
|
24
|
+
for (const [token, instance] of options.register ?? []) {
|
|
25
|
+
child.registerInstance(token, instance);
|
|
26
|
+
}
|
|
27
|
+
const rendererRegistry = child.resolve(UiRendererRegistry);
|
|
28
|
+
if (!rendererRegistry.hasDefault()) {
|
|
29
|
+
rendererRegistry.setDefault(new PreactRenderer());
|
|
30
|
+
}
|
|
31
|
+
this.container = child;
|
|
32
|
+
const httpServerProvider = new HttpServerProvider();
|
|
33
|
+
const expressProvider = new ExpressProvider(httpServerProvider);
|
|
34
|
+
registerUiControllers(options.controllers, { baseContainer: child, expressProvider });
|
|
35
|
+
this.server = httpServerProvider.getHttpServer();
|
|
36
|
+
}
|
|
37
|
+
static async create(options) {
|
|
38
|
+
const harness = new UiHarness(options);
|
|
39
|
+
await harness.listen();
|
|
40
|
+
return harness;
|
|
41
|
+
}
|
|
42
|
+
listen() {
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
this.server.once('error', reject);
|
|
45
|
+
this.server.listen(0, '127.0.0.1', () => {
|
|
46
|
+
const address = this.server.address();
|
|
47
|
+
if (!address || typeof address === 'string') {
|
|
48
|
+
reject(new Error('UiHarness: could not determine server port'));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.baseUrl = `http://127.0.0.1:${address.port}`;
|
|
52
|
+
resolve();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
get url() {
|
|
57
|
+
return this.baseUrl;
|
|
58
|
+
}
|
|
59
|
+
/** GET a view; returns the rendered HTML document. */
|
|
60
|
+
get(path, options = {}) {
|
|
61
|
+
return this.request('GET', path, options);
|
|
62
|
+
}
|
|
63
|
+
/** POST to an @action route (e.g. "/my/ui/_action/addTodo"). */
|
|
64
|
+
action(path, body, options = {}) {
|
|
65
|
+
return this.request('POST', path, { ...options, body });
|
|
66
|
+
}
|
|
67
|
+
async request(method, path, options = {}) {
|
|
68
|
+
const url = new URL(path, this.baseUrl);
|
|
69
|
+
for (const [key, value] of Object.entries(options.query ?? {})) {
|
|
70
|
+
url.searchParams.set(key, value);
|
|
71
|
+
}
|
|
72
|
+
const headers = { ...options.headers };
|
|
73
|
+
let body;
|
|
74
|
+
if (options.body !== undefined) {
|
|
75
|
+
headers['Content-Type'] = headers['Content-Type'] ?? 'application/json';
|
|
76
|
+
body = JSON.stringify(options.body);
|
|
77
|
+
}
|
|
78
|
+
const response = await fetch(url, {
|
|
79
|
+
method: method.toUpperCase(),
|
|
80
|
+
headers,
|
|
81
|
+
body,
|
|
82
|
+
redirect: options.redirect ?? 'follow',
|
|
83
|
+
});
|
|
84
|
+
const text = await response.text();
|
|
85
|
+
return {
|
|
86
|
+
status: response.status,
|
|
87
|
+
text,
|
|
88
|
+
headers: response.headers,
|
|
89
|
+
json: () => (text ? JSON.parse(text) : null),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async close() {
|
|
93
|
+
await new Promise((resolve, reject) => {
|
|
94
|
+
this.server.close((err) => (err ? reject(err) : resolve()));
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function createUiHarness(options) {
|
|
99
|
+
return UiHarness.create(options);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { UiHarness, createUiHarness };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { getIslandMeta, isIsland, island, setIslandId } from '../feature/ui-controller/island/island.js';
|
|
2
|
+
export { actionUrl, callAction } from '../feature/ui-controller/actions.js';
|
|
3
|
+
export { Outlet } from '../addon/ui/preact/outlet.js';
|
|
4
|
+
export { Fragment, cloneElement, createContext, h as createElement, createRef, h, isValidElement, toChildArray } from 'preact';
|
|
5
|
+
export * from 'preact/hooks';
|
|
6
|
+
export { Signal, batch, computed, createModel, effect, signal, action as signalAction, untracked, useComputed, useModel, useSignal, useSignalEffect } from '@preact/signals';
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { DependencyContainer } from 'tsyringe';
|
|
2
|
+
import { Request, Response, Express } from 'express';
|
|
3
|
+
import { Server } from 'node:http';
|
|
4
|
+
import * as preact from 'preact';
|
|
5
|
+
export { ComponentChild, ComponentChildren, Fragment, RefObject, VNode, cloneElement, createContext, h as createElement, createRef, h, isValidElement, toChildArray } from 'preact';
|
|
6
|
+
export * from 'preact/hooks';
|
|
7
|
+
export { Model, ModelConstructor, ReadonlySignal, Signal, batch, computed, createModel, effect, signal, action as signalAction, untracked, useComputed, useModel, useSignal, useSignalEffect } from '@preact/signals';
|
|
8
|
+
|
|
9
|
+
type IConstructor<T> = new (...args: any[]) => T;
|
|
10
|
+
|
|
11
|
+
interface IMiddleware {
|
|
12
|
+
handle(req: Request, res: Response, container: DependencyContainer): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare class HttpServerProvider {
|
|
16
|
+
server: Server | null;
|
|
17
|
+
private listening;
|
|
18
|
+
private logger;
|
|
19
|
+
getHttpServer(): Server;
|
|
20
|
+
listen(): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare class ExpressProvider {
|
|
24
|
+
private httpServerProvider;
|
|
25
|
+
private expressApp;
|
|
26
|
+
private logger;
|
|
27
|
+
constructor(httpServerProvider: HttpServerProvider);
|
|
28
|
+
getExpress(): Express;
|
|
29
|
+
listen(): void;
|
|
30
|
+
private createExpress;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** A resource to `<link rel="preload">` (font, critical image, …). */
|
|
34
|
+
interface IPreloadLink {
|
|
35
|
+
href: string;
|
|
36
|
+
/** Destination: 'font' | 'image' | 'style' | 'script' | 'fetch' | … */
|
|
37
|
+
as: string;
|
|
38
|
+
/** MIME type, e.g. 'font/woff2'. Recommended so the preload matches the request. */
|
|
39
|
+
type?: string;
|
|
40
|
+
/**
|
|
41
|
+
* CORS mode. Fonts are always fetched cross-origin, so `as: 'font'` defaults to
|
|
42
|
+
* `true` (a bare `crossorigin`) — omitting it would fetch the font twice.
|
|
43
|
+
*/
|
|
44
|
+
crossorigin?: boolean | 'anonymous' | 'use-credentials';
|
|
45
|
+
media?: string;
|
|
46
|
+
}
|
|
47
|
+
/** An origin to `<link rel="preconnect">` (e.g. a font CDN). */
|
|
48
|
+
type IPreconnect = string | {
|
|
49
|
+
href: string;
|
|
50
|
+
crossorigin?: boolean;
|
|
51
|
+
};
|
|
52
|
+
/** Extra `<head>` resource hints rendered on full document loads. */
|
|
53
|
+
interface IControllerHead {
|
|
54
|
+
/** Origins to open a connection to early (TLS handshake), e.g. a font host. */
|
|
55
|
+
preconnect?: IPreconnect[];
|
|
56
|
+
/** Resources to fetch early in parallel (fonts, hero image, …). */
|
|
57
|
+
preload?: IPreloadLink[];
|
|
58
|
+
}
|
|
59
|
+
interface IUiControllerConfig {
|
|
60
|
+
/** Base path every view/action of the controller is mounted under. */
|
|
61
|
+
path: string;
|
|
62
|
+
/** Middlewares (e.g. auth guards) applied to every view and action. */
|
|
63
|
+
middlewares?: IConstructor<IMiddleware>[];
|
|
64
|
+
/**
|
|
65
|
+
* Opt into client-side ("boosted") navigation between this controller's
|
|
66
|
+
* views: links within the controller's `path` are intercepted and swapped in
|
|
67
|
+
* without a full browser reload, backed by a stale-while-revalidate cache.
|
|
68
|
+
* Views still SSR normally and keep working without JS. Defaults to false.
|
|
69
|
+
*/
|
|
70
|
+
app?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Persistent app shell rendered once around every view of the controller. The
|
|
73
|
+
* layout renders an `<Outlet/>` where the current view goes; during boosted
|
|
74
|
+
* navigation only the outlet swaps, so the shell (and its islands) keep their
|
|
75
|
+
* state. A renderer component (e.g. a Preact function component).
|
|
76
|
+
*/
|
|
77
|
+
layout?: unknown;
|
|
78
|
+
/**
|
|
79
|
+
* `<head>` resource hints (preconnect/preload) rendered on full document
|
|
80
|
+
* loads — the natural home for app-wide fonts, since the head persists across
|
|
81
|
+
* boosted navigation and is cached for the whole session.
|
|
82
|
+
*/
|
|
83
|
+
head?: IControllerHead;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare function uiController(config: string | IUiControllerConfig): (target: IConstructor<any>) => void;
|
|
87
|
+
|
|
88
|
+
interface IViewConfig {
|
|
89
|
+
/** Sub-path appended to the controller path. Empty/omitted = controller index. */
|
|
90
|
+
path?: string;
|
|
91
|
+
/** Document <title> for this page. */
|
|
92
|
+
title?: string;
|
|
93
|
+
/** Extra <meta> tags rendered into the document head: name -> content. */
|
|
94
|
+
meta?: Record<string, string>;
|
|
95
|
+
/**
|
|
96
|
+
* Stale-while-revalidate hints for boosted navigation (`app: true`
|
|
97
|
+
* controllers). Only meaningful for the soft-nav client cache.
|
|
98
|
+
*/
|
|
99
|
+
swr?: {
|
|
100
|
+
/**
|
|
101
|
+
* Seconds a cached fragment is considered fresh: within this window a
|
|
102
|
+
* revisit renders from cache without a background revalidation. Default 0
|
|
103
|
+
* (always revalidate in the background).
|
|
104
|
+
*/
|
|
105
|
+
maxAge?: number;
|
|
106
|
+
/**
|
|
107
|
+
* Cheap revalidation tag (the SWR key). When provided, boosted-nav
|
|
108
|
+
* revalidation compares this against `If-None-Match` and can answer 304
|
|
109
|
+
* *without* running the view handler or SSR. Receives the request with
|
|
110
|
+
* body+query+params merged, so parameterized routes can (and should) key off
|
|
111
|
+
* their route params — e.g. `version: ({ id }) => docRevision(id)`.
|
|
112
|
+
* Return a short, deterministic string (a data timestamp or revision).
|
|
113
|
+
*/
|
|
114
|
+
version?: (request: any) => string | Promise<string>;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
declare function view(config?: string | IViewConfig): (target: object, propertyKey: string | symbol) => void;
|
|
119
|
+
|
|
120
|
+
interface IActionConfig {
|
|
121
|
+
/** Sub-path of the action. Defaults to the method name. Mounted under `<controller>/_action/<path>`. */
|
|
122
|
+
path?: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
declare function action(config?: string | IActionConfig): (target: object, propertyKey: string | symbol) => void;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Attach a middleware (e.g. an auth guard) to a single @view or @action.
|
|
129
|
+
* Controller-wide middlewares can instead be declared on @uiController({ middlewares }).
|
|
130
|
+
*/
|
|
131
|
+
declare function uiMiddleware(middlewareConstructor: IConstructor<IMiddleware>): (target: object, propertyKey: string | symbol) => void;
|
|
132
|
+
|
|
133
|
+
interface IUiControllerMetadata {
|
|
134
|
+
controllerConstructor: IConstructor<any>;
|
|
135
|
+
path: string;
|
|
136
|
+
middlewares: IConstructor<IMiddleware>[];
|
|
137
|
+
/** Whether this controller opts into client-side ("boosted") navigation. */
|
|
138
|
+
app?: boolean;
|
|
139
|
+
/** Persistent app-shell component rendered around every view (with an `<Outlet/>`). */
|
|
140
|
+
layout?: unknown;
|
|
141
|
+
/** `<head>` resource hints (preconnect/preload) for full document loads. */
|
|
142
|
+
head?: IControllerHead;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
interface IViewMetadata {
|
|
146
|
+
controllerConstructor: IConstructor<any>;
|
|
147
|
+
functionName: string;
|
|
148
|
+
config?: IViewConfig;
|
|
149
|
+
paramsTypes: any[];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
interface IActionMetadata {
|
|
153
|
+
controllerConstructor: IConstructor<any>;
|
|
154
|
+
functionName: string;
|
|
155
|
+
config?: IActionConfig;
|
|
156
|
+
paramsTypes: any[];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
interface IUiMiddlewareMetadata {
|
|
160
|
+
controllerConstructor: IConstructor<any>;
|
|
161
|
+
functionName: string;
|
|
162
|
+
middlewareConstructor: IConstructor<IMiddleware>;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
declare class UiControllerMetadataStore {
|
|
166
|
+
private controllers;
|
|
167
|
+
private views;
|
|
168
|
+
private actions;
|
|
169
|
+
private middlewares;
|
|
170
|
+
saveControllerMetadata(metadata: IUiControllerMetadata): void;
|
|
171
|
+
saveViewMetadata(metadata: IViewMetadata): void;
|
|
172
|
+
saveActionMetadata(metadata: IActionMetadata): void;
|
|
173
|
+
saveMiddlewareMetadata(metadata: IUiMiddlewareMetadata): void;
|
|
174
|
+
getAllUiControllerConstructors(): IConstructor<any>[];
|
|
175
|
+
private getController;
|
|
176
|
+
private collectMethodMiddlewares;
|
|
177
|
+
getControllerViewsInfo(controllerConstructor: IConstructor<any>): {
|
|
178
|
+
controllerConstructor: IConstructor<any>;
|
|
179
|
+
controller: IUiControllerMetadata;
|
|
180
|
+
middlewares: IUiMiddlewareMetadata[];
|
|
181
|
+
functionName: string;
|
|
182
|
+
config?: IViewConfig;
|
|
183
|
+
paramsTypes: any[];
|
|
184
|
+
}[];
|
|
185
|
+
getControllerActionsInfo(controllerConstructor: IConstructor<any>): {
|
|
186
|
+
controllerConstructor: IConstructor<any>;
|
|
187
|
+
controller: IUiControllerMetadata;
|
|
188
|
+
middlewares: IUiMiddlewareMetadata[];
|
|
189
|
+
functionName: string;
|
|
190
|
+
config?: IActionConfig;
|
|
191
|
+
paramsTypes: any[];
|
|
192
|
+
}[];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
interface IRenderContext {
|
|
196
|
+
/** True while running under the dev server (enables hydration in dev, etc.). */
|
|
197
|
+
dev?: boolean;
|
|
198
|
+
/**
|
|
199
|
+
* Optional layout component to wrap the view in (the persistent app shell).
|
|
200
|
+
* The renderer places the view where the layout renders its `<Outlet/>`.
|
|
201
|
+
* Passed only for full-document loads; omitted for boosted-nav fragments so
|
|
202
|
+
* only the view (the outlet's content) is rendered.
|
|
203
|
+
*/
|
|
204
|
+
layout?: unknown;
|
|
205
|
+
}
|
|
206
|
+
interface IRenderedIsland {
|
|
207
|
+
/** Stable island id (module-derived), used to load its client bundle. */
|
|
208
|
+
id: string;
|
|
209
|
+
/** Serializable props the island was rendered with, for client hydration. */
|
|
210
|
+
props: unknown;
|
|
211
|
+
}
|
|
212
|
+
interface IRenderResult {
|
|
213
|
+
/** Server-rendered HTML for the view body. */
|
|
214
|
+
html: string;
|
|
215
|
+
/** Islands encountered while rendering, in document order. */
|
|
216
|
+
islands: IRenderedIsland[];
|
|
217
|
+
/** Style hrefs (or inline CSS ids) the page depends on, if any. */
|
|
218
|
+
styles: string[];
|
|
219
|
+
}
|
|
220
|
+
interface IIslandEntryArgs {
|
|
221
|
+
/** Stable island id (also the client bundle's output name). */
|
|
222
|
+
id: string;
|
|
223
|
+
/** Absolute path to the island's source module (default export = island). */
|
|
224
|
+
importPath: string;
|
|
225
|
+
}
|
|
226
|
+
/** Renderer-specific knobs the island bundler needs to build client bundles. */
|
|
227
|
+
interface IUiClientConfig {
|
|
228
|
+
/** Module the generated island entry imports its hydration `registerIsland` from. */
|
|
229
|
+
runtimeModule: string;
|
|
230
|
+
/** esbuild JSX settings for compiling islands on the client. */
|
|
231
|
+
esbuildJsx?: {
|
|
232
|
+
jsx?: 'automatic' | 'transform' | 'preserve';
|
|
233
|
+
jsxImportSource?: string;
|
|
234
|
+
jsxFactory?: string;
|
|
235
|
+
jsxFragmentFactory?: string;
|
|
236
|
+
};
|
|
237
|
+
/** Source of the client entry that registers one island for hydration. */
|
|
238
|
+
islandEntrySource(args: IIslandEntryArgs): string;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* A pluggable UI rendering engine. The default implementation is Preact
|
|
242
|
+
* (`@wabot-dev/framework/ui`), but any framework can be adapted by implementing
|
|
243
|
+
* this interface and registering it in {@link UiRendererRegistry}.
|
|
244
|
+
*/
|
|
245
|
+
interface UiRenderer {
|
|
246
|
+
/** Unique id, e.g. "preact" or "react". */
|
|
247
|
+
readonly id: string;
|
|
248
|
+
/** Render a view's returned node tree to HTML, collecting island usage. */
|
|
249
|
+
renderToString(node: unknown, context?: IRenderContext): IRenderResult | Promise<IRenderResult>;
|
|
250
|
+
/** Bundling/hydration config. Required to ship interactive islands. */
|
|
251
|
+
readonly client?: IUiClientConfig;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
declare class UiRendererRegistry {
|
|
255
|
+
private renderers;
|
|
256
|
+
private defaultRenderer;
|
|
257
|
+
/** Register a renderer. The first one registered becomes the default. */
|
|
258
|
+
register(renderer: UiRenderer): void;
|
|
259
|
+
/** Register a renderer and make it the default. */
|
|
260
|
+
setDefault(renderer: UiRenderer): void;
|
|
261
|
+
has(id: string): boolean;
|
|
262
|
+
hasDefault(): boolean;
|
|
263
|
+
get(id?: string): UiRenderer;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Marker attached to components wrapped with {@link island}. The UI renderer
|
|
268
|
+
* uses it to decide which components must hydrate on the client; the bundler
|
|
269
|
+
* uses {@link IslandMeta.id} (assigned from the `*.island.tsx` file location) to
|
|
270
|
+
* emit a per-island client bundle.
|
|
271
|
+
*/
|
|
272
|
+
declare const ISLAND_MARKER: unique symbol;
|
|
273
|
+
interface IslandMeta {
|
|
274
|
+
/** The original component, rendered for SSR and hydrated on the client. */
|
|
275
|
+
component: (props: any) => any;
|
|
276
|
+
/** Human-readable name (component name unless overridden). */
|
|
277
|
+
name: string;
|
|
278
|
+
/** Stable bundle id, assigned during island discovery. Undefined until then. */
|
|
279
|
+
id?: string;
|
|
280
|
+
}
|
|
281
|
+
interface IslandComponent<P = any> {
|
|
282
|
+
(props: P): any;
|
|
283
|
+
[ISLAND_MARKER]: IslandMeta;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Mark a component as an interactive client "island". The component still
|
|
287
|
+
* renders on the server, but only islands ship JavaScript and hydrate in the
|
|
288
|
+
* browser. Islands must be the export of a `*.island.tsx` file so the bundler
|
|
289
|
+
* can give them a stable id.
|
|
290
|
+
*
|
|
291
|
+
* // Counter.island.tsx
|
|
292
|
+
* function Counter() { ... }
|
|
293
|
+
* export default island(Counter)
|
|
294
|
+
*/
|
|
295
|
+
declare function island<P>(component: (props: P) => any, name?: string): IslandComponent<P>;
|
|
296
|
+
declare function getIslandMeta(component: unknown): IslandMeta | undefined;
|
|
297
|
+
declare function isIsland(component: unknown): boolean;
|
|
298
|
+
/** Assign the stable bundle id to an island, done during island discovery. */
|
|
299
|
+
declare function setIslandId(component: unknown, id: string): void;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Serialize the props an island was rendered with so the client can hydrate it
|
|
303
|
+
* with the same data. Drops `children`/`ref`/`key` and any function-valued
|
|
304
|
+
* props (event handlers belong inside the island, not in its serialized props).
|
|
305
|
+
*/
|
|
306
|
+
declare function serializeProps(props: Record<string, unknown>): string;
|
|
307
|
+
declare function deserializeProps(raw: string | undefined | null): Record<string, unknown>;
|
|
308
|
+
|
|
309
|
+
interface IDiscoveredIsland {
|
|
310
|
+
/** Stable id derived from the file's project-relative path. */
|
|
311
|
+
id: string;
|
|
312
|
+
/** Absolute path to the island source module. */
|
|
313
|
+
importPath: string;
|
|
314
|
+
/** Project-relative posix path (the basis of the id). */
|
|
315
|
+
relPath: string;
|
|
316
|
+
}
|
|
317
|
+
/** Files matching this are treated as islands (default export wrapped with island()). */
|
|
318
|
+
declare const ISLAND_FILE_PATTERN: RegExp;
|
|
319
|
+
/** Deterministic, readable, collision-resistant id from a project-relative path. */
|
|
320
|
+
declare function toIslandId(relPath: string): string;
|
|
321
|
+
declare function isIslandFile(file: string): boolean;
|
|
322
|
+
/**
|
|
323
|
+
* Discovers `*.island.tsx` modules, assigns each a stable id, and stamps that
|
|
324
|
+
* id onto the imported island component (ESM module singletons mean the view
|
|
325
|
+
* renders the same instance, so the renderer can read the id during SSR).
|
|
326
|
+
*/
|
|
327
|
+
declare class IslandRegistry {
|
|
328
|
+
private islands;
|
|
329
|
+
private logger;
|
|
330
|
+
discover(files: string[], cwd?: string): Promise<IDiscoveredIsland[]>;
|
|
331
|
+
register(island: IDiscoveredIsland): void;
|
|
332
|
+
list(): IDiscoveredIsland[];
|
|
333
|
+
get(id: string): IDiscoveredIsland | undefined;
|
|
334
|
+
get size(): number;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
interface IDocumentOptions {
|
|
338
|
+
/** Server-rendered HTML placed inside <body>. */
|
|
339
|
+
bodyHtml: string;
|
|
340
|
+
/** Document title. */
|
|
341
|
+
title?: string;
|
|
342
|
+
/** <meta name=.. content=..> tags. */
|
|
343
|
+
meta?: Record<string, string>;
|
|
344
|
+
/** Stylesheet hrefs rendered as <link rel="stylesheet">. */
|
|
345
|
+
styles?: string[];
|
|
346
|
+
/** Extra <link> tags (preload/preconnect/…) as attribute maps. `true` => bare attribute. */
|
|
347
|
+
links?: Array<Record<string, string | boolean>>;
|
|
348
|
+
/** Module script srcs rendered as <script type="module">. */
|
|
349
|
+
scripts?: string[];
|
|
350
|
+
/** Raw HTML appended to <head> (e.g. inline bootstrap data). */
|
|
351
|
+
headHtml?: string;
|
|
352
|
+
/** Raw HTML appended to the end of <body> (e.g. dev live-reload snippet). */
|
|
353
|
+
bodyEndHtml?: string;
|
|
354
|
+
/** <html lang>. Defaults to "en". */
|
|
355
|
+
lang?: string;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Render the default HTML document shell around a view's body. Kept
|
|
359
|
+
* renderer-agnostic (plain string templating) so it works with any UiRenderer.
|
|
360
|
+
*/
|
|
361
|
+
declare function renderDocument(options: IDocumentOptions): string;
|
|
362
|
+
|
|
363
|
+
declare const REDIRECT_MARKER: unique symbol;
|
|
364
|
+
interface UiRedirect {
|
|
365
|
+
readonly [REDIRECT_MARKER]: true;
|
|
366
|
+
location: string;
|
|
367
|
+
status: number;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Return this from a @view or @action to send an HTTP redirect instead of
|
|
371
|
+
* rendering. Used for the post/redirect/get pattern after form actions.
|
|
372
|
+
*/
|
|
373
|
+
declare function redirect(location: string, status?: number): UiRedirect;
|
|
374
|
+
declare function isRedirect(value: unknown): value is UiRedirect;
|
|
375
|
+
|
|
376
|
+
/** Escape text for safe interpolation into HTML element content. */
|
|
377
|
+
declare function escapeHtml(value: string): string;
|
|
378
|
+
/** Escape a value for safe interpolation into a double-quoted HTML attribute. */
|
|
379
|
+
declare function escapeAttr(value: string): string;
|
|
380
|
+
|
|
381
|
+
/** Build the URL of an @action: `<controllerPath>/_action/<actionName>`. */
|
|
382
|
+
declare function actionUrl(controllerPath: string, actionName: string): string;
|
|
383
|
+
interface ICallActionOptions {
|
|
384
|
+
headers?: Record<string, string>;
|
|
385
|
+
signal?: AbortSignal;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* POST JSON to an @action and return its JSON result. Throws on non-2xx with
|
|
389
|
+
* the server-provided error message. Intended for use from islands; plain
|
|
390
|
+
* <form action=…> posts also work for progressive enhancement.
|
|
391
|
+
*/
|
|
392
|
+
declare function callAction<T = unknown>(url: string, data?: unknown, options?: ICallActionOptions): Promise<T>;
|
|
393
|
+
|
|
394
|
+
/** Page-level assets (scripts/styles) to inject, computed from the islands a view rendered. */
|
|
395
|
+
interface IPageAssets {
|
|
396
|
+
scripts?: string[];
|
|
397
|
+
styles?: string[];
|
|
398
|
+
headHtml?: string;
|
|
399
|
+
bodyEndHtml?: string;
|
|
400
|
+
/** URL of the boosted-navigation runtime; injected on `app: true` pages. */
|
|
401
|
+
navScript?: string;
|
|
402
|
+
}
|
|
403
|
+
interface IRegisterUiControllersOptions {
|
|
404
|
+
baseContainer?: DependencyContainer;
|
|
405
|
+
expressProvider?: ExpressProvider;
|
|
406
|
+
/** Hook used by the bundler/dev server to inject island client bundles + CSS. */
|
|
407
|
+
pageAssets?: (islands: IRenderedIsland[]) => IPageAssets;
|
|
408
|
+
}
|
|
409
|
+
declare function registerUiControllers(controllers: IConstructor<any>[], options?: IRegisterUiControllersOptions): ExpressProvider;
|
|
410
|
+
declare function runUiControllers(controllers: IConstructor<any>[], options?: IRegisterUiControllersOptions): void;
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Placeholder a controller `layout` renders where the current view goes. Emits a
|
|
414
|
+
* `<wabot-outlet>` host wrapping the view's server HTML; during boosted
|
|
415
|
+
* navigation only this element's content is swapped, so the surrounding shell
|
|
416
|
+
* (and its islands) keep their state.
|
|
417
|
+
*
|
|
418
|
+
* function Layout() {
|
|
419
|
+
* return <div class="app"><Nav /><main><Outlet /></main></div>
|
|
420
|
+
* }
|
|
421
|
+
* @uiController({ path: '/panel', app: true, layout: Layout })
|
|
422
|
+
*/
|
|
423
|
+
declare function Outlet(): preact.VNode<preact.Attributes & {
|
|
424
|
+
'data-wabot-outlet': string;
|
|
425
|
+
}>;
|
|
426
|
+
|
|
427
|
+
export { type IActionConfig, type IActionMetadata, type ICallActionOptions, type IControllerHead, type IDiscoveredIsland, type IDocumentOptions, type IIslandEntryArgs, type IPageAssets, type IPreconnect, type IPreloadLink, type IRegisterUiControllersOptions, type IRenderContext, type IRenderResult, type IRenderedIsland, ISLAND_FILE_PATTERN, ISLAND_MARKER, type IUiClientConfig, type IUiControllerConfig, type IUiControllerMetadata, type IUiMiddlewareMetadata, type IViewConfig, type IViewMetadata, type IslandComponent, type IslandMeta, IslandRegistry, Outlet, REDIRECT_MARKER, UiControllerMetadataStore, type UiRedirect, type UiRenderer, UiRendererRegistry, action, actionUrl, callAction, deserializeProps, escapeAttr, escapeHtml, getIslandMeta, isIsland, isIslandFile, isRedirect, island, redirect, registerUiControllers, renderDocument, runUiControllers, serializeProps, setIslandId, toIslandId, uiController, uiMiddleware, view };
|