@kingsleyweb/bun-ui 0.0.0-stage → 3.0.0-rc.2
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/LICENSE +21 -0
- package/README.md +80 -2
- package/app/docs/App.tsx +72 -0
- package/app/docs/api/client.ts +303 -0
- package/app/docs/api/contract.ts +24 -0
- package/app/docs/api/docs.ts +38 -0
- package/app/docs/api/errors.ts +144 -0
- package/app/docs/boot.tsx +58 -0
- package/app/docs/components/Badge.tsx +65 -0
- package/app/docs/components/Button.tsx +37 -0
- package/app/docs/components/Card.tsx +41 -0
- package/app/docs/components/ConfirmDialog.tsx +173 -0
- package/app/docs/components/CopyButton.tsx +68 -0
- package/app/docs/components/Dialog.tsx +230 -0
- package/app/docs/components/EmptyState.tsx +34 -0
- package/app/docs/components/ErrorView.tsx +70 -0
- package/app/docs/components/Field.tsx +93 -0
- package/app/docs/components/JsonEditor.tsx +151 -0
- package/app/docs/components/JsonView.tsx +338 -0
- package/app/docs/components/KeyValue.tsx +63 -0
- package/app/docs/components/ProblemBanner.tsx +116 -0
- package/app/docs/components/ScreenErrorBoundary.tsx +141 -0
- package/app/docs/components/Spinner.tsx +33 -0
- package/app/docs/components/Table.tsx +33 -0
- package/app/docs/components/Tabs.tsx +226 -0
- package/app/docs/components/classNames.ts +4 -0
- package/app/docs/components/components.css +691 -0
- package/app/docs/components/copy.ts +89 -0
- package/app/docs/components/fieldContext.ts +29 -0
- package/app/docs/components/inputValues.ts +142 -0
- package/app/docs/components/inputs.tsx +387 -0
- package/app/docs/components/jsonParse.ts +338 -0
- package/app/docs/components/listKeys.ts +30 -0
- package/app/docs/config.ts +86 -0
- package/app/docs/context.ts +33 -0
- package/app/docs/embed.ts +74 -0
- package/app/docs/env.d.ts +2 -0
- package/app/docs/format.ts +9 -0
- package/app/docs/hooks/useUrlTab.ts +16 -0
- package/app/docs/main.tsx +11 -0
- package/app/docs/queryClient.ts +54 -0
- package/app/docs/router.tsx +194 -0
- package/app/docs/routing.ts +194 -0
- package/app/docs/screens/docs/document.ts +27 -0
- package/app/docs/screens/docs/http/OperationView.tsx +407 -0
- package/app/docs/screens/docs/http/Sidebar.tsx +190 -0
- package/app/docs/screens/docs/http/TryItPanel.tsx +603 -0
- package/app/docs/screens/docs/http/http.css +405 -0
- package/app/docs/screens/docs/http/index.tsx +395 -0
- package/app/docs/screens/docs/http/model.ts +604 -0
- package/app/docs/screens/docs/http/tryIt.ts +455 -0
- package/app/docs/screens/docs/permissions.ts +6 -0
- package/app/docs/screens/docs/schema/Prose.tsx +43 -0
- package/app/docs/screens/docs/schema/SchemaTree.tsx +319 -0
- package/app/docs/screens/docs/schema/index.ts +30 -0
- package/app/docs/screens/docs/schema/resolve.ts +466 -0
- package/app/docs/screens/docs/schema/schema.css +137 -0
- package/app/docs/screens/docs/schema/skeleton.ts +92 -0
- package/app/docs/screens/docs/viewer.tsx +154 -0
- package/app/docs/screens/docs/ws/InlineText.tsx +25 -0
- package/app/docs/screens/docs/ws/PayloadSchema.tsx +39 -0
- package/app/docs/screens/docs/ws/format.ts +82 -0
- package/app/docs/screens/docs/ws/index.tsx +286 -0
- package/app/docs/screens/docs/ws/items.tsx +786 -0
- package/app/docs/screens/docs/ws/model.ts +1178 -0
- package/app/docs/screens/docs/ws/panels.tsx +440 -0
- package/app/docs/screens/docs/ws/ws.css +231 -0
- package/app/docs/shortcuts.ts +94 -0
- package/app/docs/styles/base.css +847 -0
- package/app/docs/styles/tokens.css +143 -0
- package/app/docs/theme.ts +56 -0
- package/app/kit/unauthorized.ts +222 -0
- package/dist/docs/assets/main-0rchxtv5.js +18 -0
- package/dist/docs/assets/main-0rchxtv5.js.map +99 -0
- package/dist/docs/assets/main-cqgyvs86.css +1 -0
- package/dist/docs/manifest.json +26 -0
- package/dist/jobs/assets/AddFlowDialog-h6xkgx9b.js +6 -0
- package/dist/jobs/assets/AddFlowDialog-h6xkgx9b.js.map +11 -0
- package/dist/jobs/assets/AddFlowDialog-n7gtc84v.css +1 -0
- package/dist/jobs/assets/added-cbwsxv3e.js +4 -0
- package/dist/jobs/assets/added-cbwsxv3e.js.map +11 -0
- package/dist/jobs/assets/bodies-yyw5hmrp.js +6 -0
- package/dist/jobs/assets/bodies-yyw5hmrp.js.map +10 -0
- package/dist/jobs/assets/channel-tgkvqm8y.js +4 -0
- package/dist/jobs/assets/channel-tgkvqm8y.js.map +10 -0
- package/dist/jobs/assets/channelChecks-s4yz4yhw.js +4 -0
- package/dist/jobs/assets/channelChecks-s4yz4yhw.js.map +10 -0
- package/dist/jobs/assets/index-02427smp.css +1 -0
- package/dist/jobs/assets/index-09z2cjft.js +4 -0
- package/dist/jobs/assets/index-09z2cjft.js.map +16 -0
- package/dist/jobs/assets/index-18bn0gvy.css +1 -0
- package/dist/jobs/assets/index-47pxmyxn.js +4 -0
- package/dist/jobs/assets/index-47pxmyxn.js.map +10 -0
- package/dist/jobs/assets/index-4e55z986.js +4 -0
- package/dist/jobs/assets/index-4e55z986.js.map +11 -0
- package/dist/jobs/assets/index-5c933424.js +4 -0
- package/dist/jobs/assets/index-5c933424.js.map +18 -0
- package/dist/jobs/assets/index-5kbyqspm.css +1 -0
- package/dist/jobs/assets/index-5ng37hk6.css +1 -0
- package/dist/jobs/assets/index-5w8w7fvc.css +1 -0
- package/dist/jobs/assets/index-71qs5qyx.css +1 -0
- package/dist/jobs/assets/index-btpg4r8b.css +1 -0
- package/dist/jobs/assets/index-d5r5n0mm.js +4 -0
- package/dist/jobs/assets/index-d5r5n0mm.js.map +23 -0
- package/dist/jobs/assets/index-e0yy2skq.css +1 -0
- package/dist/jobs/assets/index-hs60b25v.js +10 -0
- package/dist/jobs/assets/index-hs60b25v.js.map +62 -0
- package/dist/jobs/assets/index-k2smrr70.js +4 -0
- package/dist/jobs/assets/index-k2smrr70.js.map +9 -0
- package/dist/jobs/assets/index-q24jw3w9.js +4 -0
- package/dist/jobs/assets/index-q24jw3w9.js.map +32 -0
- package/dist/jobs/assets/index-qfb80xen.css +1 -0
- package/dist/jobs/assets/index-rtynx6wj.js +4 -0
- package/dist/jobs/assets/index-rtynx6wj.js.map +10 -0
- package/dist/jobs/assets/live-6k7s6358.js +4 -0
- package/dist/jobs/assets/live-6k7s6358.js.map +10 -0
- package/dist/jobs/assets/main-0jmeh6mq.js +6 -0
- package/dist/jobs/assets/main-0jmeh6mq.js.map +12 -0
- package/dist/jobs/assets/main-3yj6bv90.js +5 -0
- package/dist/jobs/assets/main-3yj6bv90.js.map +10 -0
- package/dist/jobs/assets/main-4g69fn3x.js +5 -0
- package/dist/jobs/assets/main-4g69fn3x.js.map +10 -0
- package/dist/jobs/assets/main-4gte3eqq.js +5 -0
- package/dist/jobs/assets/main-4gte3eqq.js.map +10 -0
- package/dist/jobs/assets/main-4j1fcevh.js +5 -0
- package/dist/jobs/assets/main-4j1fcevh.js.map +10 -0
- package/dist/jobs/assets/main-54qwkz28.css +1 -0
- package/dist/jobs/assets/main-5grjvsy7.js +5 -0
- package/dist/jobs/assets/main-5grjvsy7.js.map +11 -0
- package/dist/jobs/assets/main-5zbx60gq.js +5 -0
- package/dist/jobs/assets/main-5zbx60gq.js.map +11 -0
- package/dist/jobs/assets/main-9prgjhg4.js +5 -0
- package/dist/jobs/assets/main-9prgjhg4.js.map +10 -0
- package/dist/jobs/assets/main-a250ffk7.js +17 -0
- package/dist/jobs/assets/main-a250ffk7.js.map +115 -0
- package/dist/jobs/assets/main-d6ge7w08.js +5 -0
- package/dist/jobs/assets/main-d6ge7w08.js.map +10 -0
- package/dist/jobs/assets/main-gngzht43.js +5 -0
- package/dist/jobs/assets/main-gngzht43.js.map +10 -0
- package/dist/jobs/assets/main-hg0hrg8j.js +5 -0
- package/dist/jobs/assets/main-hg0hrg8j.js.map +10 -0
- package/dist/jobs/assets/main-hm1ng3yg.js +5 -0
- package/dist/jobs/assets/main-hm1ng3yg.js.map +12 -0
- package/dist/jobs/assets/main-jkvd92z9.js +5 -0
- package/dist/jobs/assets/main-jkvd92z9.js.map +10 -0
- package/dist/jobs/assets/main-jv5xqd13.js +5 -0
- package/dist/jobs/assets/main-jv5xqd13.js.map +21 -0
- package/dist/jobs/assets/main-jxre7w93.js +5 -0
- package/dist/jobs/assets/main-jxre7w93.js.map +23 -0
- package/dist/jobs/assets/main-kwmqkjfx.js +5 -0
- package/dist/jobs/assets/main-kwmqkjfx.js.map +11 -0
- package/dist/jobs/assets/main-n9cf6bxm.js +5 -0
- package/dist/jobs/assets/main-n9cf6bxm.js.map +11 -0
- package/dist/jobs/assets/main-pegp0ygb.js +5 -0
- package/dist/jobs/assets/main-pegp0ygb.js.map +10 -0
- package/dist/jobs/assets/main-qr573853.js +5 -0
- package/dist/jobs/assets/main-qr573853.js.map +12 -0
- package/dist/jobs/assets/main-rq97rdr4.js +4 -0
- package/dist/jobs/assets/main-rq97rdr4.js.map +22 -0
- package/dist/jobs/assets/main-szjdmydc.js +5 -0
- package/dist/jobs/assets/main-szjdmydc.js.map +13 -0
- package/dist/jobs/assets/main-tnbhrm9n.js +7 -0
- package/dist/jobs/assets/main-tnbhrm9n.js.map +11 -0
- package/dist/jobs/assets/main-ts19j4n0.js +5 -0
- package/dist/jobs/assets/main-ts19j4n0.js.map +25 -0
- package/dist/jobs/assets/main-w93x1dzs.js +5 -0
- package/dist/jobs/assets/main-w93x1dzs.js.map +10 -0
- package/dist/jobs/assets/sections-0ksdxs8m.css +1 -0
- package/dist/jobs/assets/sections-0y7w4fb4.js +4 -0
- package/dist/jobs/assets/sections-0y7w4fb4.js.map +10 -0
- package/dist/jobs/assets/sse-mn0t0fh7.js +5 -0
- package/dist/jobs/assets/sse-mn0t0fh7.js.map +11 -0
- package/dist/jobs/assets/sseChecks-t7tcm7ra.js +4 -0
- package/dist/jobs/assets/sseChecks-t7tcm7ra.js.map +10 -0
- package/dist/jobs/assets/validation-ysjfy072.js +4 -0
- package/dist/jobs/assets/validation-ysjfy072.js.map +9 -0
- package/dist/jobs/manifest.json +511 -0
- package/dts/docs/assets.d.ts +144 -0
- package/dts/docs/assets.d.ts.map +1 -0
- package/dts/docs/browser/config.d.ts +61 -0
- package/dts/docs/browser/config.d.ts.map +1 -0
- package/dts/docs/browser/index.d.ts +12 -0
- package/dts/docs/browser/index.d.ts.map +1 -0
- package/dts/docs/docsUi.d.ts +42 -0
- package/dts/docs/docsUi.d.ts.map +1 -0
- package/dts/docs/hosted.d.ts +22 -0
- package/dts/docs/hosted.d.ts.map +1 -0
- package/dts/docs/index.d.ts +18 -0
- package/dts/docs/index.d.ts.map +1 -0
- package/dts/docs/shell.d.ts +57 -0
- package/dts/docs/shell.d.ts.map +1 -0
- package/dts/docs/types.d.ts +137 -0
- package/dts/docs/types.d.ts.map +1 -0
- package/dts/index.d.ts +21 -0
- package/dts/index.d.ts.map +1 -0
- package/dts/jobs/assets.d.ts +157 -0
- package/dts/jobs/assets.d.ts.map +1 -0
- package/dts/jobs/browser/config.d.ts +67 -0
- package/dts/jobs/browser/config.d.ts.map +1 -0
- package/dts/jobs/browser/index.d.ts +10 -0
- package/dts/jobs/browser/index.d.ts.map +1 -0
- package/dts/jobs/browser/unauthorized.d.ts +9 -0
- package/dts/jobs/browser/unauthorized.d.ts.map +1 -0
- package/dts/jobs/index.d.ts +24 -0
- package/dts/jobs/index.d.ts.map +1 -0
- package/dts/jobs/jobsUi.d.ts +63 -0
- package/dts/jobs/jobsUi.d.ts.map +1 -0
- package/dts/jobs/shell.d.ts +77 -0
- package/dts/jobs/shell.d.ts.map +1 -0
- package/dts/jobs/types.d.ts +146 -0
- package/dts/jobs/types.d.ts.map +1 -0
- package/dts/kit/browser/shared.d.ts +10 -0
- package/dts/kit/browser/shared.d.ts.map +1 -0
- package/dts/kit/browser/unauthorized.d.ts +74 -0
- package/dts/kit/browser/unauthorized.d.ts.map +1 -0
- package/dts/kit/unauthorized.d.ts +47 -0
- package/dts/kit/unauthorized.d.ts.map +1 -0
- package/guides/docs.md +170 -0
- package/guides/jobs.md +1120 -0
- package/lib/docs/assets.ts +427 -0
- package/lib/docs/browser/config.ts +66 -0
- package/lib/docs/browser/index.ts +24 -0
- package/lib/docs/docsUi.ts +623 -0
- package/lib/docs/hosted.ts +31 -0
- package/lib/docs/index.ts +37 -0
- package/lib/docs/shell.ts +156 -0
- package/lib/docs/types.ts +149 -0
- package/lib/index.ts +27 -0
- package/lib/jobs/assets.ts +448 -0
- package/lib/jobs/browser/config.ts +65 -0
- package/lib/jobs/browser/index.ts +9 -0
- package/lib/jobs/browser/unauthorized.ts +11 -0
- package/lib/jobs/index.ts +41 -0
- package/lib/jobs/jobsUi.ts +709 -0
- package/lib/jobs/shell.ts +205 -0
- package/lib/jobs/types.ts +162 -0
- package/lib/kit/browser/shared.ts +11 -0
- package/lib/kit/browser/unauthorized.ts +114 -0
- package/lib/kit/unauthorized.ts +222 -0
- package/package.json +198 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../lib/jobs/browser/config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,YAAY,EAAE,OAAO,EAAE,CAAC;AAExB,0FAA0F;AAC1F,eAAO,MAAM,yBAAyB,uBAAuB,CAAC;AAE9D,kDAAkD;AAClD,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,MAAM,EAAE,OAAO,CAAC;IAChB,0EAA0E;IAC1E,IAAI,EAAE,OAAO,CAAC;CACf;AAED,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,gFAAgF;IAChF,OAAO,EAAE,CAAC,CAAC;IACX,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,2GAA2G;IAC3G,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;;OAKG;IACH,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IACxD,2EAA2E;IAC3E,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC1D,kCAAkC;IAClC,QAAQ,EAAE,cAAc,CAAC;IACzB,6BAA6B;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf;;;;OAIG;IACH,YAAY,EAAE,cAAc,GAAG,IAAI,CAAC;CACrC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@kingsleyweb/bun-ui/jobs/browser`: the jobs UI's browser-safe contract,
|
|
3
|
+
* what `jobsUi()` inlines into the page and the app reads before its first
|
|
4
|
+
* request. No runtime import beyond constants and no domain package, so a
|
|
5
|
+
* browser bundle (or a host reading the injected config) may import it.
|
|
6
|
+
*/
|
|
7
|
+
export type { JobsUiConfig, JobsUiSections, UiTheme } from "./config.js";
|
|
8
|
+
export { JOBS_UI_CONFIG_ELEMENT_ID } from "./config.js";
|
|
9
|
+
export type { UiUnauthorized, UiUnauthorizedStatus } from "./unauthorized.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../lib/jobs/browser/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `unauthorized` option's shared types, re-exported from the kit
|
|
3
|
+
* (`lib/kit/browser/unauthorized.ts`), which `docsUi()` uses too, as it does
|
|
4
|
+
* the code both run: validation and the shell's `303` (`lib/kit/unauthorized`),
|
|
5
|
+
* and the browser's redirect (`app/kit/unauthorized`). Types only, so
|
|
6
|
+
* `lib/jobs/browser` stays free of runtime imports.
|
|
7
|
+
*/
|
|
8
|
+
export type { UiUnauthorized, UiUnauthorizedStatus, } from "../../kit/browser/unauthorized.js";
|
|
9
|
+
//# sourceMappingURL=unauthorized.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unauthorized.d.ts","sourceRoot":"","sources":["../../../lib/jobs/browser/unauthorized.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,YAAY,EACV,cAAc,EACd,oBAAoB,GACrB,MAAM,gCAAgC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { ASSET_CACHE_CONTROL, DEFAULT_BASE_PATH, DEFAULT_TITLE, jobsUi, } from "./jobsUi.js";
|
|
2
|
+
/**
|
|
3
|
+
* `@kingsleyweb/bun-ui/jobs`: a management UI and API documentation viewer
|
|
4
|
+
* for the `@kingsleyweb/bun-jobs` management API. Needs
|
|
5
|
+
* `@kingsleyweb/bun-jobs`, an optional peer of the package that this entry
|
|
6
|
+
* (and `./lib/jobs/*`) alone requires.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const api = createJobsApi({ jobs, basePath: "/jobs-api", authorize });
|
|
10
|
+
* const ui = jobsUi({ api, basePath: "/jobs" });
|
|
11
|
+
* app.use(api.basePath, api.router);
|
|
12
|
+
* app.use(ui.basePath, ui.router);
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* The bundle machinery (`lib/jobs/assets.ts`: building, writing and loading
|
|
16
|
+
* `dist/jobs/`) is internal: `scripts/build.ts` and the tests import it directly.
|
|
17
|
+
* `JobsUiBaseOptions` stays public because both option interfaces extend it,
|
|
18
|
+
* so it is part of the options' declared shape.
|
|
19
|
+
*/
|
|
20
|
+
export type { UiUnauthorized, UiUnauthorizedStatus, } from "./browser/unauthorized.js";
|
|
21
|
+
export type { JobsUiConfig, JobsUiSections, UiTheme } from "./browser/config.js";
|
|
22
|
+
export { JOBS_UI_CONFIG_ELEMENT_ID } from "./browser/config.js";
|
|
23
|
+
export type { JobsUi, JobsUiApiOptions, JobsUiUnauthorizedOptions, JobsUiAuthorize, JobsUiAuthorizeContext, JobsUiAuthorizeResult, JobsUiBaseOptions, JobsUiOptions, JobsUiUrlOptions, } from "./types.js";
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/jobs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,MAAM,GACP,MAAM,UAAU,CAAC;AAClB;;;;;;;;;;;;;;;;;GAiBG;AACH,YAAY,EACV,cAAc,EACd,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EACV,MAAM,EACN,gBAAgB,EAChB,yBAAyB,EACzB,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,GACjB,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { JobsUi, JobsUiOptions } from "./types.js";
|
|
2
|
+
import { ASSET_CACHE_CONTROL } from "../kit/browser/shared.js";
|
|
3
|
+
/** The UI's default mount path. */
|
|
4
|
+
export declare const DEFAULT_BASE_PATH = "/jobs";
|
|
5
|
+
/** The default page title. */
|
|
6
|
+
export declare const DEFAULT_TITLE = "Jobs";
|
|
7
|
+
/** The path under `basePath` the bundle is served from. */
|
|
8
|
+
export declare const ASSETS_SUBPATH = "/assets";
|
|
9
|
+
export { ASSET_CACHE_CONTROL };
|
|
10
|
+
export { DEFAULT_RETURN_PARAM, DEFAULT_UNAUTHORIZED_STATUSES, } from "../kit/browser/unauthorized.js";
|
|
11
|
+
/** Where the bundle comes from; tests point these at a fixture. */
|
|
12
|
+
export interface JobsUiInternals {
|
|
13
|
+
/** The dist directory read when present. Defaults to the package's `dist/`. */
|
|
14
|
+
distDir?: string;
|
|
15
|
+
/** The entry built in memory without a dist. Defaults to `app/main.tsx`. */
|
|
16
|
+
entry?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Validates and normalises an absolute mount path, as the API validates its
|
|
20
|
+
* `basePath`: absolute, trailing slashes dropped, not `"/"`, and only
|
|
21
|
+
* segments of letters, digits, `_`, `.`, `~` and `-`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeBasePath(value: unknown, what: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* The read-only summary a newer API exposes as `api.info` (bun-jobs'
|
|
26
|
+
* `JobsApiInfo`). Typed structurally and feature-detected, so the UI works
|
|
27
|
+
* with an API that predates it and prefers it once it is there.
|
|
28
|
+
*/
|
|
29
|
+
export interface JobsApiInfoLike {
|
|
30
|
+
/** The API's CSRF settings; `header` is lower-cased, `null` for none. */
|
|
31
|
+
csrf?: {
|
|
32
|
+
header?: string | null;
|
|
33
|
+
};
|
|
34
|
+
/** Full paths of the spec documents actually routed, or `null` when docs are off. */
|
|
35
|
+
docs?: {
|
|
36
|
+
openapi: string;
|
|
37
|
+
asyncapi?: string;
|
|
38
|
+
} | null;
|
|
39
|
+
/** The socket's full path and, for a dedicated socket, its bound port; `null` without one. */
|
|
40
|
+
websocket?: {
|
|
41
|
+
path: string;
|
|
42
|
+
port?: number;
|
|
43
|
+
} | null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Creates the UI with an explicit bundle source. {@link jobsUi} is this with
|
|
47
|
+
* the package's own `dist/` and `app/main.tsx`; tests point it at a fixture.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createJobsUi(options: JobsUiOptions, internals?: JobsUiInternals): JobsUi;
|
|
50
|
+
/**
|
|
51
|
+
* Creates the management UI: validates the options (throwing `ConfigError`
|
|
52
|
+
* for anything unusable), resolves the configuration the app is given, and
|
|
53
|
+
* builds the router.
|
|
54
|
+
*
|
|
55
|
+
* ```ts
|
|
56
|
+
* const api = createJobsApi({ jobs, basePath: "/admin/jobs-api", authorize });
|
|
57
|
+
* const ui = jobsUi({ api, basePath: "/admin/jobs" });
|
|
58
|
+
* app.use(api.basePath, api.router);
|
|
59
|
+
* app.use(ui.basePath, ui.router);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function jobsUi(options: JobsUiOptions): JobsUi;
|
|
63
|
+
//# sourceMappingURL=jobsUi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jobsUi.d.ts","sourceRoot":"","sources":["../../lib/jobs/jobsUi.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EACV,MAAM,EAGN,aAAa,EACd,MAAM,SAAS,CAAC;AAIjB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAa5D,mCAAmC;AACnC,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAEzC,8BAA8B;AAC9B,eAAO,MAAM,aAAa,SAAS,CAAC;AAEpC,2DAA2D;AAC3D,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAU/B,OAAO,EACL,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,6BAA6B,CAAC;AAErC,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAyBtE;AAgGD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAClC,qFAAqF;IACrF,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACrD,8FAA8F;IAC9F,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACpD;AA2OD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,aAAa,EACtB,SAAS,GAAE,eAAoB,GAC9B,MAAM,CA4OR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAErD"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { UiAssets } from "./assets.js";
|
|
2
|
+
/**
|
|
3
|
+
* The HTML shell: the one page every client route answers with, and the
|
|
4
|
+
* Content-Security-Policy it is served under.
|
|
5
|
+
*
|
|
6
|
+
* Everything in it is fixed per mount except the nonce, which is fresh per
|
|
7
|
+
* request. The configuration travels as a nonce'd
|
|
8
|
+
* `<script type="application/json">`, escaped for a script context, so a title
|
|
9
|
+
* containing `</script>` cannot end the element early.
|
|
10
|
+
*/
|
|
11
|
+
import type { JobsUiConfig } from "./browser/config.js";
|
|
12
|
+
/** A fresh CSP nonce: 128 random bits, base64. */
|
|
13
|
+
export declare function createNonce(): string;
|
|
14
|
+
/** Escapes text for an HTML text node or a quoted attribute value. */
|
|
15
|
+
export declare function escapeHtml(value: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Serialises a value as JSON that is safe inside a `<script>` element: `<`,
|
|
18
|
+
* `>` and `&` become `<`/`>`/`&` (so neither `</script>` nor
|
|
19
|
+
* `<!--` can appear), and U+2028/U+2029 are escaped too. The result is still
|
|
20
|
+
* valid JSON that parses back to the same value.
|
|
21
|
+
*/
|
|
22
|
+
export declare function jsonForScript(value: unknown): string;
|
|
23
|
+
/** Inputs to {@link cspHeader}. */
|
|
24
|
+
export interface CspOptions {
|
|
25
|
+
/** This request's nonce. */
|
|
26
|
+
nonce: string;
|
|
27
|
+
/**
|
|
28
|
+
* `connect-src` sources after `'self'`, usually from {@link connectSources}.
|
|
29
|
+
* A source that is not a single CSP token (whitespace, `;` or `,`) is
|
|
30
|
+
* dropped rather than written into the header. Defaults to none.
|
|
31
|
+
*/
|
|
32
|
+
connectSrc?: readonly string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The shell's Content-Security-Policy. Scripts only from this origin and
|
|
36
|
+
* carrying the nonce; styles only from files (no inline `<style>`, no `style`
|
|
37
|
+
* attributes in markup — setting `element.style` from script is still fine);
|
|
38
|
+
* connections to `'self'` plus `connectSrc`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function cspHeader(options: CspOptions): string;
|
|
41
|
+
/** Inputs to {@link connectSources}. */
|
|
42
|
+
export interface ConnectSourcesOptions {
|
|
43
|
+
/**
|
|
44
|
+
* The request's `Host` (`host[:port]`), i.e. the page's origin as the
|
|
45
|
+
* browser loaded it. Attacker-controlled on a misrouted request, so anything
|
|
46
|
+
* outside the `host[:port]` grammar is ignored, never copied into the header.
|
|
47
|
+
*/
|
|
48
|
+
host: string | undefined;
|
|
49
|
+
/** Whether the page is `https`: its socket sources are then `wss:`, else `ws:`. */
|
|
50
|
+
secure: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* The API's origin when it is elsewhere (`"https://api.example"`); added in
|
|
53
|
+
* its `http(s)` and `ws(s)` forms. Omitted for a same-origin API.
|
|
54
|
+
*/
|
|
55
|
+
apiOrigin?: string;
|
|
56
|
+
/**
|
|
57
|
+
* A dedicated socket port (`config.websocket.port`); adds that port's
|
|
58
|
+
* `ws(s)` origin on the page's hostname. Omitted when the socket shares the
|
|
59
|
+
* page's port.
|
|
60
|
+
*/
|
|
61
|
+
websocketPort?: number | null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The `connect-src` sources after `'self'`: the `ws(s)` form of the page's own
|
|
65
|
+
* origin (older WebKit does not let `'self'` match `ws:`/`wss:`), a dedicated
|
|
66
|
+
* socket port on the same hostname, and a cross-origin API in both forms.
|
|
67
|
+
* Never a bare `ws:` or `wss:`, which would allow a socket to any host.
|
|
68
|
+
*/
|
|
69
|
+
export declare function connectSources(options: ConnectSourcesOptions): string[];
|
|
70
|
+
/** A renderer for one mount: fixed parts computed once, the nonce per call. */
|
|
71
|
+
export type ShellRenderer = (nonce: string) => string;
|
|
72
|
+
/**
|
|
73
|
+
* Prepares the shell for a mount and a bundle. The returned function only
|
|
74
|
+
* splices a nonce in.
|
|
75
|
+
*/
|
|
76
|
+
export declare function createShellRenderer(config: JobsUiConfig, assets: UiAssets): ShellRenderer;
|
|
77
|
+
//# sourceMappingURL=shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../lib/jobs/shell.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,kBAAkB,CAAC;AAI9D,kDAAkD;AAClD,wBAAgB,WAAW,IAAI,MAAM,CAIpC;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOhD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAOpD;AAOD,mCAAmC;AACnC,MAAM,WAAW,UAAU;IACzB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAKD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAerD;AAWD,wCAAwC;AACxC,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,mFAAmF;IACnF,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,EAAE,CA4BvE;AAED,+EAA+E;AAC/E,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;AAEtD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,QAAQ,GACf,aAAa,CAqCf"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { BunRequest, BunRouter, LoggerLike, RouterHandler } from "@kingsleyweb/bun-common";
|
|
2
|
+
import type { JobsApi, JobsApiAuthorizeResult } from "@kingsleyweb/bun-jobs";
|
|
3
|
+
import type { UnauthorizedOptions } from "../kit/browser/unauthorized.js";
|
|
4
|
+
import type { JobsUiConfig, JobsUiSections, UiTheme } from "./browser/config.js";
|
|
5
|
+
/** What {@link JobsUiOptions.authorize} is told about the request being decided. */
|
|
6
|
+
export interface JobsUiAuthorizeContext {
|
|
7
|
+
/** `true` for a bundle file under `<basePath>/assets/`, `false` for the HTML shell. */
|
|
8
|
+
asset: boolean;
|
|
9
|
+
/** The request's full path, e.g. `"/jobs/queues/mail"` (no query string). */
|
|
10
|
+
path: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* What `authorize` answers — the same shape as the API's: `true`/`false`, or
|
|
14
|
+
* `{ allow: true }` / `{ allow: false, status?: 401 | 403, reason? }`.
|
|
15
|
+
* A denial is a 401 only when `status` is exactly `401`; any other `status`
|
|
16
|
+
* (a `429`, a `500`, a string) is a 403, as the API does — fail closed. Rate
|
|
17
|
+
* limiting belongs in `middleware`, which can answer 429 itself. Anything
|
|
18
|
+
* that is not one of these shapes denies with 403.
|
|
19
|
+
*/
|
|
20
|
+
export type JobsUiAuthorizeResult = JobsApiAuthorizeResult;
|
|
21
|
+
/**
|
|
22
|
+
* Decides whether a request may load the UI. May be async; a throw (or a
|
|
23
|
+
* rejection) is a 500. A denial is 401 for `status: 401` and 403 for every
|
|
24
|
+
* other status — see {@link JobsUiAuthorizeResult}.
|
|
25
|
+
*/
|
|
26
|
+
export type JobsUiAuthorize = (req: BunRequest, context: JobsUiAuthorizeContext) => JobsUiAuthorizeResult | Promise<JobsUiAuthorizeResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Where to send the browser when an authorization check fails, instead of
|
|
29
|
+
* leaving it on a page whose screens report the failure. See
|
|
30
|
+
* {@link JobsUiBaseOptions.unauthorized}; the fields are described on
|
|
31
|
+
* `UnauthorizedOptions`, which `docsUi()` takes too.
|
|
32
|
+
*/
|
|
33
|
+
export type JobsUiUnauthorizedOptions = UnauthorizedOptions;
|
|
34
|
+
/** Options shared by both ways of pointing the UI at its API. */
|
|
35
|
+
export interface JobsUiBaseOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Header every mutation must carry, as the API's `csrf.header`, or `false`
|
|
38
|
+
* for none (`config.csrfHeader` is then `null`). Unset: what `api` reports
|
|
39
|
+
* once the API exposes it (`api.info.csrf.header`, feature-detected), else
|
|
40
|
+
* none (`config.csrfHeader: null`). Until the API reports it, set it by hand
|
|
41
|
+
* to match the API's `csrf.header`.
|
|
42
|
+
*/
|
|
43
|
+
csrfHeader?: string | false;
|
|
44
|
+
/**
|
|
45
|
+
* Absolute path the UI is mounted at: no trailing slash, not `"/"`, segments
|
|
46
|
+
* of letters, digits, `_`, `.`, `~` and `-`. Must not equal or sit under
|
|
47
|
+
* the API's `basePath`. Defaults to `"/jobs"`.
|
|
48
|
+
*/
|
|
49
|
+
basePath?: string;
|
|
50
|
+
/** Page title and brand text. Defaults to `"Jobs"`. */
|
|
51
|
+
title?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Sections to enable. Each defaults to `true`; switching both off is a
|
|
54
|
+
* `ConfigError`.
|
|
55
|
+
*/
|
|
56
|
+
sections?: Partial<JobsUiSections>;
|
|
57
|
+
/**
|
|
58
|
+
* Guards the shell and the bundle — **not** the data, which the API's own
|
|
59
|
+
* `authorize` protects. Same result shape as the API's, and fails closed
|
|
60
|
+
* the same way: a denial is 401 only for `status: 401` and 403 for any
|
|
61
|
+
* other status (`429` included), an unrecognised answer is 403 and a throw
|
|
62
|
+
* is 500. Omitted: everyone may load the page.
|
|
63
|
+
*/
|
|
64
|
+
authorize?: JobsUiAuthorize;
|
|
65
|
+
/**
|
|
66
|
+
* Sends the browser to a sign-in (or any other) page when the caller is not
|
|
67
|
+
* authorized, instead of showing the failure on every screen. Off by
|
|
68
|
+
* default (today's behaviour: the shell answers a problem, screens show
|
|
69
|
+
* their messages).
|
|
70
|
+
*
|
|
71
|
+
* With it set, for a status in `statuses` (`[401]` by default):
|
|
72
|
+
*
|
|
73
|
+
* - **The shell:** a browser navigation (`GET`/`HEAD` of a page, not a
|
|
74
|
+
* bundle file) that `authorize` denies answers `303 See Other` to `redirectTo`.
|
|
75
|
+
* A bundle file, and a request that is not a navigation (a script's
|
|
76
|
+
* `fetch`, an `Accept` without `text/html`), keep the problem answer.
|
|
77
|
+
* - **The app:** the first API call (any query or mutation) or live-events
|
|
78
|
+
* message that fails with such a status sends the browser to `redirectTo` with
|
|
79
|
+
* `location.assign`, once per page load.
|
|
80
|
+
*
|
|
81
|
+
* A denial `middleware` answers itself is not redirected: only
|
|
82
|
+
* `authorize`'s. The target is fixed here, never read from the request, so
|
|
83
|
+
* it cannot be an open redirect. See {@link JobsUiUnauthorizedOptions}.
|
|
84
|
+
*/
|
|
85
|
+
unauthorized?: JobsUiUnauthorizedOptions;
|
|
86
|
+
/**
|
|
87
|
+
* Middleware run before every UI route, on the `GET`/`HEAD` requests the UI
|
|
88
|
+
* answers (session loading, a rate limiter). Runs before `authorize`.
|
|
89
|
+
* Defaults to none.
|
|
90
|
+
*/
|
|
91
|
+
middleware?: readonly RouterHandler[];
|
|
92
|
+
/** Initial colour scheme. Defaults to `"system"` (follows `prefers-color-scheme`). */
|
|
93
|
+
theme?: UiTheme;
|
|
94
|
+
/**
|
|
95
|
+
* Where the bundle comes from. Unset (default): the prebuilt `dist/` when
|
|
96
|
+
* present, else an in-memory `Bun.build` on the first request. `true`:
|
|
97
|
+
* always build in memory. `false`: `dist/` is required — `jobsUi()` throws
|
|
98
|
+
* a `ConfigError` without it.
|
|
99
|
+
*/
|
|
100
|
+
dev?: boolean;
|
|
101
|
+
/** Logger, or anything `resolveLogger` accepts. Defaults to a console logger. */
|
|
102
|
+
logger?: LoggerLike;
|
|
103
|
+
}
|
|
104
|
+
/** `jobsUi()` beside a `createJobsApi` in the same process. */
|
|
105
|
+
export interface JobsUiApiOptions extends JobsUiBaseOptions {
|
|
106
|
+
/**
|
|
107
|
+
* The API this UI manages. Its `basePath`, WebSocket path/port and docs
|
|
108
|
+
* paths are read from it.
|
|
109
|
+
*/
|
|
110
|
+
api: JobsApi;
|
|
111
|
+
/** Not with `api`. */
|
|
112
|
+
apiUrl?: never;
|
|
113
|
+
}
|
|
114
|
+
/** `jobsUi()` for an API in another process or on another origin. */
|
|
115
|
+
export interface JobsUiUrlOptions extends JobsUiBaseOptions {
|
|
116
|
+
/**
|
|
117
|
+
* Base URL of the API, no trailing slash needed: a same-origin absolute
|
|
118
|
+
* path (`"/jobs-api"`) or an `http(s)://` URL. Either way the path follows
|
|
119
|
+
* `basePath`'s segment rules (checked on the string as written, so `..`, a
|
|
120
|
+
* space or `%2F` is refused rather than normalised away) and may not carry
|
|
121
|
+
* a query or a fragment; a URL may not carry credentials, and its path may
|
|
122
|
+
* be empty (the API at the origin root). The WebSocket and docs paths are
|
|
123
|
+
* then discovered by the app from `/meta` at runtime (`config.websocket`
|
|
124
|
+
* and `config.docs` are `null`). A URL's origin is added to the CSP's
|
|
125
|
+
* `connect-src` in `http(s)` and `ws(s)` form. A cross-origin API needs
|
|
126
|
+
* CORS, CSRF and WebSocket origins configured on its side.
|
|
127
|
+
*/
|
|
128
|
+
apiUrl: string;
|
|
129
|
+
/** Not with `apiUrl`. */
|
|
130
|
+
api?: never;
|
|
131
|
+
}
|
|
132
|
+
/** Options for `jobsUi()`: exactly one of `api` and `apiUrl`. */
|
|
133
|
+
export type JobsUiOptions = JobsUiApiOptions | JobsUiUrlOptions;
|
|
134
|
+
/** A mountable UI. */
|
|
135
|
+
export interface JobsUi {
|
|
136
|
+
/**
|
|
137
|
+
* Serves the shell and the bundle. Mount with `use(ui.basePath, ui.router)`,
|
|
138
|
+
* on a bun-common or a bun-nest adapter.
|
|
139
|
+
*/
|
|
140
|
+
readonly router: BunRouter;
|
|
141
|
+
/** The normalised `basePath`, no trailing slash. */
|
|
142
|
+
readonly basePath: string;
|
|
143
|
+
/** The configuration injected into every page, frozen. */
|
|
144
|
+
readonly config: Readonly<JobsUiConfig>;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../lib/jobs/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,aAAa,EACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE9E,oFAAoF;AACpF,MAAM,WAAW,sBAAsB;IACrC,uFAAuF;IACvF,KAAK,EAAE,OAAO,CAAC;IACf,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAC5B,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,sBAAsB,KAC5B,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GAAG,mBAAmB,CAAC;AAE5D,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACnC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,YAAY,CAAC,EAAE,yBAAyB,CAAC;IACzC;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACtC,sFAAsF;IACtF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,iFAAiF;IACjF,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD;;;OAGG;IACH,GAAG,EAAE,OAAO,CAAC;IACb,sBAAsB;IACtB,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED,qEAAqE;AACrE,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD;;;;;;;;;;;OAWG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,GAAG,CAAC,EAAE,KAAK,CAAC;CACb;AAED,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AAEhE,sBAAsB;AACtB,MAAM,WAAW,MAAM;IACrB;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;CACzC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What every UI of the package shares and a browser may import: no runtime
|
|
3
|
+
* import, no domain package. The root entry (`@kingsleyweb/bun-ui`) and each
|
|
4
|
+
* UI's `/<ui>/browser` entry re-export from here.
|
|
5
|
+
*/
|
|
6
|
+
/** Colour scheme a UI starts in. `"system"` follows `prefers-color-scheme`. */
|
|
7
|
+
export type UiTheme = "system" | "light" | "dark";
|
|
8
|
+
/** `Cache-Control` for hashed bundle files: their name changes with their content. */
|
|
9
|
+
export declare const ASSET_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
10
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../lib/kit/browser/shared.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,+EAA+E;AAC/E,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAElD,sFAAsF;AACtF,eAAO,MAAM,mBAAmB,wCAAwC,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `unauthorized` option: where to send the browser when the caller turns
|
|
3
|
+
* out not to be signed in. Shared by `docsUi()` and `jobsUi()`,
|
|
4
|
+
* on both sides of each: the server (the shell's 303) and the app (an API
|
|
5
|
+
* 401). Types, defaults and pure functions only, with no runtime imports: the
|
|
6
|
+
* apps bundle this file for the browser.
|
|
7
|
+
*/
|
|
8
|
+
/** A status that can trigger the redirect: 401 (not signed in) or 403 (not allowed). */
|
|
9
|
+
export type UiUnauthorizedStatus = 401 | 403;
|
|
10
|
+
/**
|
|
11
|
+
* The `unauthorized` option as a host writes it: where to send the browser
|
|
12
|
+
* when an authorization check fails, instead of leaving it on a page that
|
|
13
|
+
* reports the failure.
|
|
14
|
+
*/
|
|
15
|
+
export interface UnauthorizedOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Where to go: a path on this host starting with one `/` (`"/login"`,
|
|
18
|
+
* `"/auth/sign-in?app=jobs"`), or an absolute `http:`/`https:` URL (an
|
|
19
|
+
* identity provider's sign-in page). Required. A path inside the UI's own
|
|
20
|
+
* `basePath` is a `ConfigError`: the UI would redirect to itself.
|
|
21
|
+
* `javascript:`, `data:`, `//host` and anything else are refused.
|
|
22
|
+
*/
|
|
23
|
+
redirectTo: string;
|
|
24
|
+
/**
|
|
25
|
+
* Query parameter that carries the page the user was on, so the sign-in
|
|
26
|
+
* page can send them back: path, query and (in the browser) fragment,
|
|
27
|
+
* always a relative URL starting with one `/` (e.g.
|
|
28
|
+
* `/login?returnTo=%2Fdocs%2Fhttp`). `false` adds nothing. Defaults to
|
|
29
|
+
* `"returnTo"`. Letters, digits, `_`, `.`, `~` and `-` only. The sign-in
|
|
30
|
+
* page must still check the value before redirecting to it.
|
|
31
|
+
*/
|
|
32
|
+
returnParam?: string | false;
|
|
33
|
+
/**
|
|
34
|
+
* Which failures redirect. Defaults to `[401]`: only "not signed in". A 403
|
|
35
|
+
* means signed in but not allowed, which the page explains itself; add
|
|
36
|
+
* `403` to redirect on that too. Must be a non-empty array of `401` and
|
|
37
|
+
* `403`.
|
|
38
|
+
*/
|
|
39
|
+
statuses?: readonly UiUnauthorizedStatus[];
|
|
40
|
+
}
|
|
41
|
+
/** The resolved `unauthorized` option, as the browser receives it in the page's config. */
|
|
42
|
+
export interface UiUnauthorized {
|
|
43
|
+
/** The target: a path (`"/login"`) or an absolute `http(s)` URL, validated on the server. */
|
|
44
|
+
redirectTo: string;
|
|
45
|
+
/** The query parameter that carries the in-app location back, or `null` for none. */
|
|
46
|
+
returnParam: string | null;
|
|
47
|
+
/** The statuses that redirect, ascending and without repeats (`[401]` by default). */
|
|
48
|
+
statuses: readonly UiUnauthorizedStatus[];
|
|
49
|
+
}
|
|
50
|
+
/** `unauthorized.returnParam` when unset. */
|
|
51
|
+
export declare const DEFAULT_RETURN_PARAM = "returnTo";
|
|
52
|
+
/** `unauthorized.statuses` when unset: only "not signed in". */
|
|
53
|
+
export declare const DEFAULT_UNAUTHORIZED_STATUSES: readonly UiUnauthorizedStatus[];
|
|
54
|
+
/**
|
|
55
|
+
* Whether a value read back from a page's config has the shape of a
|
|
56
|
+
* {@link UiUnauthorized}: enough that a stale or hand-edited shell fails with
|
|
57
|
+
* a message instead of a broken redirect. The server validated the values.
|
|
58
|
+
*/
|
|
59
|
+
export declare function isUiUnauthorized(value: unknown): value is UiUnauthorized;
|
|
60
|
+
/**
|
|
61
|
+
* Makes an in-app location safe to hand back as a relative URL: it starts
|
|
62
|
+
* with exactly one `/` (never `//` or `/\`, which a browser reads as another
|
|
63
|
+
* host). Anything not starting with `/` becomes `/`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function relativeReturnPath(location: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* The URL to send the browser to: `redirectTo`, with `returnParam` set to
|
|
68
|
+
* `returnPath` (made relative by {@link relativeReturnPath}) when both are
|
|
69
|
+
* given. A path target stays a path; an absolute target stays absolute. A
|
|
70
|
+
* `returnParam` already in `redirectTo`'s query is replaced, and its
|
|
71
|
+
* fragment is kept.
|
|
72
|
+
*/
|
|
73
|
+
export declare function unauthorizedRedirectUrl(redirect: Pick<UiUnauthorized, "redirectTo" | "returnParam">, returnPath: string | undefined): string;
|
|
74
|
+
//# sourceMappingURL=unauthorized.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unauthorized.d.ts","sourceRoot":"","sources":["../../../lib/kit/browser/unauthorized.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,wFAAwF;AACxF,MAAM,MAAM,oBAAoB,GAAG,GAAG,GAAG,GAAG,CAAC;AAE7C;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;CAC5C;AAED,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,6FAA6F;IAC7F,UAAU,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,sFAAsF;IACtF,QAAQ,EAAE,SAAS,oBAAoB,EAAE,CAAC;CAC3C;AAED,6CAA6C;AAC7C,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAE/C,gEAAgE;AAChE,eAAO,MAAM,6BAA6B,EAAE,SAAS,oBAAoB,EACnD,CAAC;AAEvB;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAWxE;AAKD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,GAAG,aAAa,CAAC,EAC5D,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,MAAM,CAUR"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server half of the `unauthorized` option, shared by `docsUi()` and
|
|
3
|
+
* `jobsUi()`: validating it, telling a page navigation from any other
|
|
4
|
+
* request, and answering the shell's `303`. The browser half is
|
|
5
|
+
* `app/kit/unauthorized.ts` (`./docs/embed/unauthorized`); what both need is
|
|
6
|
+
* `lib/kit/browser/unauthorized.ts`.
|
|
7
|
+
*/
|
|
8
|
+
import type { BunRequest, BunResponse } from "@kingsleyweb/bun-common";
|
|
9
|
+
import type { UiUnauthorized } from "./browser/unauthorized.js";
|
|
10
|
+
/**
|
|
11
|
+
* Builds the error a refused option throws: each caller passes its own
|
|
12
|
+
* `ConfigError` (`docsUi()` bun-common's, `jobsUi()` bun-jobs'), so a refusal
|
|
13
|
+
* is the class that caller's users already catch.
|
|
14
|
+
*/
|
|
15
|
+
export type UnauthorizedConfigError = (
|
|
16
|
+
/** What is wrong, starting with the option's name. */
|
|
17
|
+
message: string,
|
|
18
|
+
/** The offending values, for the error's context. */
|
|
19
|
+
context: Record<string, unknown>) => Error;
|
|
20
|
+
/**
|
|
21
|
+
* Validates the `unauthorized` option and fills in its defaults; `null` when
|
|
22
|
+
* it is unset (the option is off). Every refusal is thrown as `fail` builds
|
|
23
|
+
* it.
|
|
24
|
+
*
|
|
25
|
+
* @param value The option as the host passed it.
|
|
26
|
+
* @param basePath The UI's normalised `basePath`, for the redirect-loop check.
|
|
27
|
+
* @param fail Builds the caller's own `ConfigError`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveUnauthorized(value: unknown, basePath: string, fail: UnauthorizedConfigError): UiUnauthorized | null;
|
|
30
|
+
/**
|
|
31
|
+
* Whether a request is a browser navigation, the only kind a redirect helps:
|
|
32
|
+
* `Sec-Fetch-Mode: navigate` when the browser sends the header (every
|
|
33
|
+
* current one does), else an `Accept` naming `text/html`. A script's
|
|
34
|
+
* `fetch`, `curl` (whose `Accept` is the any-type wildcard) and a health
|
|
35
|
+
* probe are not, and keep the problem.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isNavigation(req: BunRequest): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Whether a denial with `status` should be answered with the redirect: the
|
|
40
|
+
* option is on, the route is a page of the shell (not a bundle file, not a
|
|
41
|
+
* document the viewer fetches), the status is listed, and the request is a
|
|
42
|
+
* navigation.
|
|
43
|
+
*/
|
|
44
|
+
export declare function redirectsDenial(redirect: UiUnauthorized | null, shell: boolean, status: number, req: BunRequest): redirect is UiUnauthorized;
|
|
45
|
+
/** Answers `303 See Other` to the sign-in target, carrying the request's own path and query back. */
|
|
46
|
+
export declare function sendUnauthorizedRedirect(req: BunRequest, res: BunResponse, redirect: UiUnauthorized): void;
|
|
47
|
+
//# sourceMappingURL=unauthorized.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unauthorized.d.ts","sourceRoot":"","sources":["../../lib/kit/unauthorized.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAC;AAOhC;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG;AACpC,sDAAsD;AACtD,OAAO,EAAE,MAAM;AACf,qDAAqD;AACrD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC7B,KAAK,CAAC;AAsFX;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,uBAAuB,GAC5B,cAAc,GAAG,IAAI,CA8CvB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAMrD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,cAAc,GAAG,IAAI,EAC/B,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,UAAU,GACd,QAAQ,IAAI,cAAc,CAO5B;AAED,qGAAqG;AACrG,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,cAAc,GACvB,IAAI,CAMN"}
|