alinea 2.0.0-preview.4 → 2.0.0-preview.5
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/.init/content/pages/welcome.json +1 -1
- package/dist/.init/src/cms.ts +1 -4
- package/dist/LICENSES.md +107 -107
- package/dist/adapter/next/cms.js +5 -1
- package/dist/adapter/next/handler.js +35 -6
- package/dist/adapter/next/previews.js +7 -1
- package/dist/adapter/next/syncCheck.d.ts +12 -0
- package/dist/adapter/next/syncCheck.js +59 -0
- package/dist/adapter/next/with-alinea.d.ts +0 -8
- package/dist/adapter/next/with-alinea.js +43 -19
- package/dist/adapter/vite/plugin.js +9 -4
- package/dist/backend/Handler.js +106 -0
- package/dist/backend/api/ProxyMedia.d.ts +3 -0
- package/dist/backend/api/ProxyMedia.js +39 -0
- package/dist/backend/api/S3Uploads.d.ts +1 -1
- package/dist/backend/router/Router.js +2 -0
- package/dist/backend/util/Syncable.js +1 -1
- package/dist/bundled.d.ts +164 -70
- package/dist/chunks/{chunk-XMOVGDFI.js → chunk-A6M3PNJT.js} +1 -1
- package/dist/cli/Generate.js +1 -3
- package/dist/cli/Serve.js +3 -2
- package/dist/cli/bin.js +1 -1
- package/dist/cli/generate/GenerateDashboard.js +1 -0
- package/dist/cli/serve/CreateLocalServer.d.ts +1 -1
- package/dist/cli/serve/CreateLocalServer.js +42 -34
- package/dist/cli/static/init/cms.js +1 -4
- package/dist/cli/util/ContentType.d.ts +1 -0
- package/dist/cli/util/ContentType.js +36 -0
- package/dist/cloud/CloudHandshake.d.ts +6 -0
- package/dist/cloud/CloudHandshake.js +67 -10
- package/dist/cloud/CloudRemote.js +24 -11
- package/dist/components/Calendar.js +4 -4
- package/dist/components/Checkbox.js +3 -3
- package/dist/components/ColorSwatchPicker.js +2 -2
- package/dist/components/ComboBox.js +9 -9
- package/dist/components/DateField.js +4 -4
- package/dist/components/DatePicker.js +3 -3
- package/dist/components/DateRangePicker.js +8 -8
- package/dist/components/Disclosure.js +7 -7
- package/dist/components/Label.js +4 -4
- package/dist/components/List.d.ts +1 -1
- package/dist/components/List.js +35 -34
- package/dist/components/Menu.js +4 -4
- package/dist/components/Modal.js +2 -2
- package/dist/components/MultipleSelect.js +23 -23
- package/dist/components/NumberField.js +6 -6
- package/dist/components/ProgressCircle.js +1 -1
- package/dist/components/SearchField.js +7 -7
- package/dist/components/Select.js +9 -9
- package/dist/components/Surface.js +2 -2
- package/dist/components/Table.js +7 -7
- package/dist/components/Tabs.js +2 -2
- package/dist/components/TagGroup.js +2 -2
- package/dist/components/TextField.js +6 -6
- package/dist/components/TimeField.js +3 -3
- package/dist/components/Toggle.js +2 -2
- package/dist/components/Toolbar.js +2 -2
- package/dist/components/Tooltip.js +2 -2
- package/dist/components/Tree.js +6 -6
- package/dist/core/Config.d.ts +10 -3
- package/dist/core/Config.js +16 -1
- package/dist/core/Graph.d.ts +2 -2
- package/dist/core/Role.js +16 -14
- package/dist/core/TextDoc.d.ts +2 -0
- package/dist/core/TextDoc.js +1 -0
- package/dist/core/Workspace.d.ts +6 -5
- package/dist/core/db/EntryIndex.d.ts +3 -0
- package/dist/core/db/EntryIndex.js +62 -0
- package/dist/core/db/EntryTransaction.js +33 -12
- package/dist/core/db/EntryUrlConflictError.js +1 -1
- package/dist/core/db/LinkResolver.d.ts +8 -2
- package/dist/core/db/LinkResolver.js +27 -5
- package/dist/core/field/RichTextField.js +16 -10
- package/dist/core/media/MediaLocation.d.ts +9 -15
- package/dist/core/media/MediaLocation.js +29 -19
- package/dist/core/media/MediaTypes.js +1 -2
- package/dist/dashboard/App.js +1 -1
- package/dist/dashboard/app/AccessDenied.js +2 -2
- package/dist/dashboard/app/ActivityStatus.js +14 -13
- package/dist/dashboard/app/AppShell.js +1 -1
- package/dist/dashboard/app/AuthView.js +9 -9
- package/dist/dashboard/app/Badge.js +2 -2
- package/dist/dashboard/app/CompactField.js +13 -13
- package/dist/dashboard/app/DashboardErrorBoundary.js +4 -4
- package/dist/dashboard/app/EntryFields.d.ts +3 -1
- package/dist/dashboard/app/EntryFields.js +11 -8
- package/dist/dashboard/app/EntryHeader.js +117 -85
- package/dist/dashboard/app/EntryHeaderActions.d.ts +21 -4
- package/dist/dashboard/app/EntryHeaderActions.js +48 -27
- package/dist/dashboard/app/EntryReferences.js +9 -9
- package/dist/dashboard/app/EntrySidebar.js +12 -12
- package/dist/dashboard/app/EntrySidebarPreview.js +11 -11
- package/dist/dashboard/app/EntryTranslationBanner.d.ts +3 -1
- package/dist/dashboard/app/EntryTranslationBanner.js +24 -21
- package/dist/dashboard/app/Explorer.d.ts +4 -2
- package/dist/dashboard/app/Explorer.js +50 -46
- package/dist/dashboard/app/ExplorerCards.js +28 -28
- package/dist/dashboard/app/ExplorerFileCard.js +19 -19
- package/dist/dashboard/app/ExplorerList.js +12 -13
- package/dist/dashboard/app/ExplorerModal.js +5 -5
- package/dist/dashboard/app/ExplorerTable.js +46 -46
- package/dist/dashboard/app/LinkPicker.js +5 -5
- package/dist/dashboard/app/LocaleMenu.d.ts +7 -0
- package/dist/dashboard/app/LocaleMenu.js +26 -10
- package/dist/dashboard/app/ReadOnlyBadge.d.ts +4 -0
- package/dist/dashboard/app/ReadOnlyBadge.js +33 -0
- package/dist/dashboard/app/SidebarTree.d.ts +3 -6
- package/dist/dashboard/app/SidebarTree.js +54 -49
- package/dist/dashboard/app/WorkspaceMenu.js +12 -12
- package/dist/dashboard/app/WorkspaceRoots.js +24 -24
- package/dist/dashboard/app/editor/FileEditor.d.ts +2 -3
- package/dist/dashboard/app/editor/FileEditor.js +31 -34
- package/dist/dashboard/app/editor/FilePreview.js +6 -6
- package/dist/dashboard/app/modals/CreateEntry.js +5 -5
- package/dist/dashboard/app/pages/EntryPage.js +73 -30
- package/dist/dashboard/app/pages/SplashPage.js +47 -47
- package/dist/dashboard/app/pages/UsersPage.js +34 -34
- package/dist/dashboard/app/ui/DashboardModal.js +18 -18
- package/dist/dashboard/app/ui/Rail.js +3 -3
- package/dist/dashboard/app/ui/Sidebar.js +2 -2
- package/dist/dashboard/atoms/activity.d.ts +0 -1
- package/dist/dashboard/atoms/activity.js +1 -2
- package/dist/dashboard/atoms/editor.d.ts +2 -1
- package/dist/dashboard/atoms/editor.js +4 -2
- package/dist/dashboard/atoms/entry.d.ts +2 -0
- package/dist/dashboard/atoms/entry.js +32 -14
- package/dist/dashboard/atoms/explorer.d.ts +4 -3
- package/dist/dashboard/atoms/explorer.js +61 -22
- package/dist/dashboard/atoms/link.d.ts +1 -1
- package/dist/dashboard/atoms/link.js +39 -55
- package/dist/dashboard/atoms/root.d.ts +7 -2
- package/dist/dashboard/atoms/root.js +51 -16
- package/dist/dashboard/atoms/upload.d.ts +1 -0
- package/dist/dashboard/atoms/upload.js +2 -1
- package/dist/dashboard/boot/DashboardWorker.js +1 -0
- package/dist/dashboard/fixture/cms.js +1 -4
- package/dist/dashboard/hook/UseSaveShortcut.d.ts +1 -0
- package/dist/dashboard/hook/UseSaveShortcut.js +24 -0
- package/dist/dashboard/hooks.d.ts +1 -1
- package/dist/dashboard/hooks.js +12 -3
- package/dist/field/code/CodeField.view.js +9 -9
- package/dist/field/link/ImageLink.js +1 -3
- package/dist/field/link/LinkField.view.js +84 -58
- package/dist/field/list/ListField.view.js +13 -13
- package/dist/field/metadata/MetadataField.d.ts +3 -3
- package/dist/field/metadata/MetadataField.view.js +24 -17
- package/dist/field/object/ObjectField.view.js +11 -4
- package/dist/field/richtext/PickTextLink.js +5 -2
- package/dist/field/richtext/ReferenceLink.d.ts +2 -0
- package/dist/field/richtext/ReferenceLink.js +5 -0
- package/dist/field/richtext/RichTextBlock.js +2 -2
- package/dist/field/richtext/RichTextExtensions.js +22 -22
- package/dist/field/richtext/RichTextField.view.js +4 -4
- package/dist/field/richtext/extensions/Link.d.ts +1 -0
- package/dist/field/richtext/extensions/Link.js +1 -0
- package/dist/field/time/TimeField.d.ts +0 -2
- package/dist/field/time/TimeField.view.js +1 -1
- package/dist/index.css +44 -38
- package/dist/next.cjs +96 -19
- package/dist/picker/entry/EntryPicker.js +10 -12
- package/dist/picker/entry/EntryReference.d.ts +2 -0
- package/dist/picker/entry/EntryReference.js +1 -0
- package/dist/types.d.ts +0 -1
- package/package.json +1 -1
package/dist/cli/Generate.js
CHANGED
|
@@ -24,9 +24,7 @@ var require2 = createRequire(import.meta.url);
|
|
|
24
24
|
var alineaPackageDir = path.dirname(require2.resolve("alinea/package.json"));
|
|
25
25
|
async function generatePackage(context, cms) {
|
|
26
26
|
const { config } = cms;
|
|
27
|
-
|
|
28
|
-
const staticFile = config.dashboardFile ? join(config.publicDir, config.dashboardFile) : void 0;
|
|
29
|
-
if (!staticFile) return;
|
|
27
|
+
const staticFile = join(config.publicDir, Config.dashboardFile(config));
|
|
30
28
|
await generateDashboard(context, cms, Config.handlerUrl(config), staticFile);
|
|
31
29
|
return basename(staticFile);
|
|
32
30
|
}
|
package/dist/cli/Serve.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
package_default
|
|
3
|
-
} from "../chunks/chunk-
|
|
3
|
+
} from "../chunks/chunk-A6M3PNJT.js";
|
|
4
4
|
import "../chunks/chunk-CQ52GEHY.js";
|
|
5
5
|
|
|
6
6
|
// src/cli/Serve.ts
|
|
@@ -24,7 +24,7 @@ async function serve(options) {
|
|
|
24
24
|
const apiKey = process.env.ALINEA_API_KEY ?? createId();
|
|
25
25
|
const nodeServer = startServer(preferredPort, 0, cmd === "build");
|
|
26
26
|
const dashboardUrl = nodeServer.then(
|
|
27
|
-
(server) => `http
|
|
27
|
+
(server) => `http://localhost:${server.port}`
|
|
28
28
|
);
|
|
29
29
|
let devServer;
|
|
30
30
|
try {
|
|
@@ -60,6 +60,7 @@ async function serve(options) {
|
|
|
60
60
|
options.onAfterGenerate?.({
|
|
61
61
|
ALINEA_DEV_SERVER: url,
|
|
62
62
|
ALINEA_ADMIN_PATH: Config.adminPath(config),
|
|
63
|
+
ALINEA_HANDLER_URL: Config.handlerUrl(config),
|
|
63
64
|
ALINEA_API_KEY: apiKey
|
|
64
65
|
});
|
|
65
66
|
});
|
package/dist/cli/bin.js
CHANGED
|
@@ -220,7 +220,7 @@ var lib_default2 = (e, t2) => new o(e, t2);
|
|
|
220
220
|
// package.json
|
|
221
221
|
var package_default = {
|
|
222
222
|
name: "alinea",
|
|
223
|
-
version: "2.0.0-preview.
|
|
223
|
+
version: "2.0.0-preview.5",
|
|
224
224
|
description: "Headless git-based CMS",
|
|
225
225
|
repository: "github:alineacms/alinea",
|
|
226
226
|
license: "MIT",
|
|
@@ -95,6 +95,7 @@ async function generateDashboard({ configLocation, rootDir, configDir }, cms, ha
|
|
|
95
95
|
define: {
|
|
96
96
|
"process.env.NODE_ENV": '"production"',
|
|
97
97
|
"process.env.ALINEA_BUILD_ID": JSON.stringify(buildId),
|
|
98
|
+
"process.env.ALINEA_FORCE_AUTH": "true",
|
|
98
99
|
...publicDefines(process.env)
|
|
99
100
|
},
|
|
100
101
|
...buildOptions,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Handler } from 'alinea/backend/Handler';
|
|
2
2
|
import type { CMS } from 'alinea/core/CMS';
|
|
3
3
|
import type { User } from 'alinea/core/User';
|
|
4
|
-
import {
|
|
4
|
+
import { Request, Response } from '@alinea/iso';
|
|
5
5
|
import type { ServeContext } from './ServeContext.js';
|
|
6
6
|
export declare function createLocalServer({ cmd, configLocation, rootDir, staticDir, alineaDev, buildOptions, production, liveReload, buildId, apiKey }: ServeContext, cms: CMS, handleApi: Handler, user: User): {
|
|
7
7
|
close(): void;
|
|
@@ -2,46 +2,19 @@ import "../../chunks/chunk-CQ52GEHY.js";
|
|
|
2
2
|
|
|
3
3
|
// src/cli/serve/CreateLocalServer.ts
|
|
4
4
|
import { router } from "alinea/backend/router/Router";
|
|
5
|
+
import { Config } from "alinea/core/Config";
|
|
5
6
|
import { HttpError } from "alinea/core/HttpError";
|
|
6
7
|
import { trigger } from "alinea/core/Trigger";
|
|
7
8
|
import { assertUploadSize } from "alinea/core/media/UploadLimits";
|
|
8
|
-
import { ReadableStream, Response } from "@alinea/iso";
|
|
9
|
+
import { ReadableStream, Request, Response } from "@alinea/iso";
|
|
9
10
|
import fs from "node:fs";
|
|
10
11
|
import path from "node:path";
|
|
11
12
|
import { buildEmitter } from "../build/BuildEmitter.js";
|
|
13
|
+
import { contentType } from "../util/ContentType.js";
|
|
12
14
|
import { ignorePlugin } from "../util/IgnorePlugin.js";
|
|
13
15
|
import { publicDefines } from "../util/PublicDefines.js";
|
|
14
16
|
import { reportFatal } from "../util/Report.js";
|
|
15
17
|
import { viewsPlugin } from "../util/ViewsPlugin.js";
|
|
16
|
-
var mimeTypes = new Map(
|
|
17
|
-
Object.entries({
|
|
18
|
-
// Text
|
|
19
|
-
".css": "text/css; charset=utf-8",
|
|
20
|
-
".htm": "text/html; charset=utf-8",
|
|
21
|
-
".html": "text/html; charset=utf-8",
|
|
22
|
-
".js": "text/javascript; charset=utf-8",
|
|
23
|
-
".json": "application/json",
|
|
24
|
-
".mjs": "text/javascript; charset=utf-8",
|
|
25
|
-
".xml": "text/xml; charset=utf-8",
|
|
26
|
-
// Images
|
|
27
|
-
".gif": "image/gif",
|
|
28
|
-
".jpeg": "image/jpeg",
|
|
29
|
-
".jpg": "image/jpeg",
|
|
30
|
-
".png": "image/png",
|
|
31
|
-
".svg": "image/svg+xml",
|
|
32
|
-
".webp": "image/webp",
|
|
33
|
-
// Fonts
|
|
34
|
-
".eot": "application/vnd.ms-fontobject",
|
|
35
|
-
".otf": "font/otf",
|
|
36
|
-
".sfnt": "font/sfnt",
|
|
37
|
-
".ttf": "font/ttf",
|
|
38
|
-
".woff": "font/woff",
|
|
39
|
-
".woff2": "font/woff2",
|
|
40
|
-
// Other
|
|
41
|
-
".pdf": "application/pdf",
|
|
42
|
-
".wasm": "application/wasm"
|
|
43
|
-
})
|
|
44
|
-
);
|
|
45
18
|
function buildFiles(outdir, result) {
|
|
46
19
|
return new Map(
|
|
47
20
|
result.outputFiles.map((file) => {
|
|
@@ -72,9 +45,11 @@ function createLocalServer({
|
|
|
72
45
|
});
|
|
73
46
|
}
|
|
74
47
|
const devDir = path.join(staticDir, "dev");
|
|
48
|
+
const publicDir = path.join(rootDir, cms.config.publicDir ?? "public");
|
|
49
|
+
const adminPath = Config.adminPath(cms.config);
|
|
75
50
|
const getPath = (url) => {
|
|
76
|
-
if (url.pathname.startsWith(
|
|
77
|
-
return url.pathname.slice(
|
|
51
|
+
if (url.pathname === adminPath || url.pathname.startsWith(`${adminPath}/`))
|
|
52
|
+
return url.pathname.slice(adminPath.length);
|
|
78
53
|
return url.pathname;
|
|
79
54
|
};
|
|
80
55
|
const matcher = router.matcher(getPath);
|
|
@@ -157,11 +132,34 @@ function createLocalServer({
|
|
|
157
132
|
const extension = path.extname(fileName);
|
|
158
133
|
return new Response(file.contents, {
|
|
159
134
|
headers: {
|
|
160
|
-
"content-type":
|
|
135
|
+
"content-type": contentType(extension),
|
|
161
136
|
etag
|
|
162
137
|
}
|
|
163
138
|
});
|
|
164
139
|
}
|
|
140
|
+
async function servePublicFile(request) {
|
|
141
|
+
if (request.method !== "GET" && request.method !== "HEAD") return;
|
|
142
|
+
const pathname = decodeURIComponent(new URL(request.url).pathname);
|
|
143
|
+
const location = path.resolve(publicDir, pathname.replace(/^[/\\]+/, ""));
|
|
144
|
+
const relative = path.relative(publicDir, location);
|
|
145
|
+
if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))
|
|
146
|
+
return;
|
|
147
|
+
try {
|
|
148
|
+
const stat = await fs.promises.stat(location);
|
|
149
|
+
if (!stat.isFile()) return;
|
|
150
|
+
const body = request.method === "HEAD" ? void 0 : await fs.promises.readFile(location);
|
|
151
|
+
return new Response(body, {
|
|
152
|
+
headers: {
|
|
153
|
+
"content-length": String(stat.size),
|
|
154
|
+
"content-type": contentType(path.extname(location))
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
} catch (error) {
|
|
158
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
159
|
+
return;
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
165
163
|
const httpRouter = router(
|
|
166
164
|
matcher.get("/~dev").map(() => {
|
|
167
165
|
const stream = new ReadableStream({
|
|
@@ -224,6 +222,15 @@ function createLocalServer({
|
|
|
224
222
|
}
|
|
225
223
|
}),
|
|
226
224
|
router.compress(
|
|
225
|
+
matcher.all("/file/*").map(({ request, params }) => {
|
|
226
|
+
if (request.method !== "GET" && request.method !== "HEAD") return;
|
|
227
|
+
const url = new URL(request.url);
|
|
228
|
+
url.pathname = "/api";
|
|
229
|
+
url.search = new URLSearchParams({
|
|
230
|
+
file: String(params.wild)
|
|
231
|
+
}).toString();
|
|
232
|
+
return devHandler(new Request(url, request));
|
|
233
|
+
}),
|
|
227
234
|
matcher.all("/api").map(async ({ url, request }) => {
|
|
228
235
|
return devHandler(request);
|
|
229
236
|
}),
|
|
@@ -245,7 +252,8 @@ function createLocalServer({
|
|
|
245
252
|
{ headers: { "content-type": "text/html" } }
|
|
246
253
|
);
|
|
247
254
|
}),
|
|
248
|
-
serveBrowserBuild
|
|
255
|
+
serveBrowserBuild,
|
|
256
|
+
servePublicFile
|
|
249
257
|
)
|
|
250
258
|
).notFound(() => new Response("Not found", { status: 404 }));
|
|
251
259
|
function uploadCorsHeaders(request) {
|
|
@@ -17,7 +17,6 @@ export const cms = createCMS({
|
|
|
17
17
|
main: Config.workspace('Example', {
|
|
18
18
|
source: 'content',
|
|
19
19
|
mediaDir: 'public/media',
|
|
20
|
-
mediaUrl: '/media',
|
|
21
20
|
roots: {
|
|
22
21
|
pages: Config.root('Example site', {
|
|
23
22
|
contains: ['Page']
|
|
@@ -39,7 +38,5 @@ export const cms = createCMS({
|
|
|
39
38
|
|
|
40
39
|
// The handler route URL
|
|
41
40
|
handlerUrl: '/api/cms',
|
|
42
|
-
|
|
43
|
-
// The admin dashboard will be bundled in this static file
|
|
44
|
-
dashboardFile: 'admin.html'
|
|
41
|
+
adminPath: '/admin'
|
|
45
42
|
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function contentType(extension: string): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import "../../chunks/chunk-CQ52GEHY.js";
|
|
2
|
+
|
|
3
|
+
// src/cli/util/ContentType.ts
|
|
4
|
+
var contentTypes = {
|
|
5
|
+
// Text
|
|
6
|
+
".css": "text/css; charset=utf-8",
|
|
7
|
+
".htm": "text/html; charset=utf-8",
|
|
8
|
+
".html": "text/html; charset=utf-8",
|
|
9
|
+
".js": "text/javascript; charset=utf-8",
|
|
10
|
+
".json": "application/json",
|
|
11
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
12
|
+
".xml": "text/xml; charset=utf-8",
|
|
13
|
+
// Images
|
|
14
|
+
".gif": "image/gif",
|
|
15
|
+
".jpeg": "image/jpeg",
|
|
16
|
+
".jpg": "image/jpeg",
|
|
17
|
+
".png": "image/png",
|
|
18
|
+
".svg": "image/svg+xml",
|
|
19
|
+
".webp": "image/webp",
|
|
20
|
+
// Fonts
|
|
21
|
+
".eot": "application/vnd.ms-fontobject",
|
|
22
|
+
".otf": "font/otf",
|
|
23
|
+
".sfnt": "font/sfnt",
|
|
24
|
+
".ttf": "font/ttf",
|
|
25
|
+
".woff": "font/woff",
|
|
26
|
+
".woff2": "font/woff2",
|
|
27
|
+
// Other
|
|
28
|
+
".pdf": "application/pdf",
|
|
29
|
+
".wasm": "application/wasm"
|
|
30
|
+
};
|
|
31
|
+
function contentType(extension) {
|
|
32
|
+
return contentTypes[extension.toLowerCase()] ?? "application/octet-stream";
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
contentType
|
|
36
|
+
};
|
|
@@ -3,5 +3,11 @@ interface VerifyCloudHandshakeOptions {
|
|
|
3
3
|
handshakeId: string;
|
|
4
4
|
origin: string;
|
|
5
5
|
}
|
|
6
|
+
export declare class CloudHandshakeError extends Error {
|
|
7
|
+
name: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class CloudHandshakeServiceError extends Error {
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
6
12
|
export declare function verifyCloudHandshake(token: string, options: VerifyCloudHandshakeOptions): Promise<void>;
|
|
7
13
|
export {};
|
|
@@ -4,25 +4,72 @@ import "../chunks/chunk-CQ52GEHY.js";
|
|
|
4
4
|
import { decode, verify } from "alinea/core/util/JWT";
|
|
5
5
|
import { isRecord } from "alinea/core/util/Objects";
|
|
6
6
|
import { cloudConfig } from "./CloudConfig.js";
|
|
7
|
+
var CloudHandshakeError = class extends Error {
|
|
8
|
+
name = "CloudHandshakeError";
|
|
9
|
+
};
|
|
10
|
+
var CloudHandshakeServiceError = class extends Error {
|
|
11
|
+
name = "CloudHandshakeServiceError";
|
|
12
|
+
};
|
|
7
13
|
var keysPromise;
|
|
8
14
|
var keysExpireAt = 0;
|
|
9
15
|
var lastForcedRefreshAt = 0;
|
|
10
16
|
var keyCacheLifetime = 5 * 60 * 1e3;
|
|
11
17
|
var forcedRefreshInterval = 60 * 1e3;
|
|
18
|
+
var verificationMessages = {
|
|
19
|
+
"Invalid signature": "Handshake token signature is invalid",
|
|
20
|
+
"Token expired": "Handshake token has expired",
|
|
21
|
+
"Token not yet valid": "Handshake token is not yet valid",
|
|
22
|
+
"Invalid exp value": "Handshake token expiration is invalid",
|
|
23
|
+
"Invalid nbf value": "Handshake token not-before claim is invalid"
|
|
24
|
+
};
|
|
12
25
|
async function verifyCloudHandshake(token, options) {
|
|
13
|
-
const { header } =
|
|
14
|
-
if (header.alg !== "RS256" || typeof header.kid !== "string")
|
|
15
|
-
throw new
|
|
26
|
+
const { header } = decodeHandshakeToken(token);
|
|
27
|
+
if (!isRecord(header) || header.alg !== "RS256" || typeof header.kid !== "string" || !header.kid)
|
|
28
|
+
throw new CloudHandshakeError("Handshake token header is invalid");
|
|
16
29
|
let key = (await cloudKeys()).find((key2) => key2.kid === header.kid);
|
|
17
30
|
if (!key) {
|
|
18
31
|
key = (await refreshCloudKeys()).find((key2) => key2.kid === header.kid);
|
|
19
32
|
}
|
|
20
|
-
if (!key)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
if (!key)
|
|
34
|
+
throw new CloudHandshakeError("Handshake token signing key is unknown");
|
|
35
|
+
const payload = await verify(token, key, { algorithms: ["RS256"] }).catch(
|
|
36
|
+
(cause) => {
|
|
37
|
+
throw verificationError(cause);
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
if (!isRecord(payload))
|
|
41
|
+
throw new CloudHandshakeError("Handshake token payload is invalid");
|
|
42
|
+
assertClaim("purpose", payload.purpose, "handshake");
|
|
43
|
+
assertClaim("ID", payload.handshake_id, options.handshakeId);
|
|
44
|
+
assertClaim("audience", payload.aud, options.clientId);
|
|
45
|
+
assertClaim("issuer", payload.iss, normalizedCloudUrl());
|
|
46
|
+
assertClaim("origin", payload.origin, options.origin);
|
|
47
|
+
if (typeof payload.project !== "string")
|
|
48
|
+
throw new CloudHandshakeError("Handshake project claim is invalid");
|
|
49
|
+
if (typeof payload.iat !== "number")
|
|
50
|
+
throw new CloudHandshakeError("Handshake issued-at claim is invalid");
|
|
51
|
+
if (typeof payload.exp !== "number")
|
|
52
|
+
throw new CloudHandshakeError("Handshake expiration claim is invalid");
|
|
53
|
+
}
|
|
54
|
+
function assertClaim(name, received, expected) {
|
|
55
|
+
if (received !== expected)
|
|
56
|
+
throw new CloudHandshakeError(
|
|
57
|
+
`Handshake ${name} mismatch: expected ${expected}, received ${String(received)}`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
function decodeHandshakeToken(token) {
|
|
61
|
+
try {
|
|
62
|
+
return decode(token);
|
|
63
|
+
} catch (cause) {
|
|
64
|
+
throw new CloudHandshakeError("Handshake token is malformed", { cause });
|
|
24
65
|
}
|
|
25
66
|
}
|
|
67
|
+
function verificationError(cause) {
|
|
68
|
+
const reason = cause instanceof Error && verificationMessages[cause.message];
|
|
69
|
+
return reason ? new CloudHandshakeError(reason, { cause }) : new CloudHandshakeServiceError("Could not verify handshake token", {
|
|
70
|
+
cause
|
|
71
|
+
});
|
|
72
|
+
}
|
|
26
73
|
function cloudKeys() {
|
|
27
74
|
if (keysPromise && (keysExpireAt === 0 || Date.now() < keysExpireAt))
|
|
28
75
|
return keysPromise;
|
|
@@ -40,16 +87,24 @@ function loadCloudKeys() {
|
|
|
40
87
|
keysExpireAt = 0;
|
|
41
88
|
keysPromise = fetch(cloudConfig.jwks).then(async (response) => {
|
|
42
89
|
if (!response.ok)
|
|
43
|
-
throw new
|
|
90
|
+
throw new CloudHandshakeServiceError(
|
|
91
|
+
`Could not load handshake signing keys: ${response.status}`
|
|
92
|
+
);
|
|
44
93
|
const body = await response.json();
|
|
45
94
|
if (!isRecord(body) || !Array.isArray(body.keys))
|
|
46
|
-
throw new
|
|
95
|
+
throw new CloudHandshakeServiceError(
|
|
96
|
+
"Cloud returned invalid handshake signing keys"
|
|
97
|
+
);
|
|
47
98
|
keysExpireAt = Date.now() + keyCacheLifetime;
|
|
48
99
|
return body.keys.filter(isCloudKey);
|
|
49
100
|
}).catch((cause) => {
|
|
50
101
|
keysPromise = void 0;
|
|
51
102
|
keysExpireAt = 0;
|
|
52
|
-
throw cause;
|
|
103
|
+
if (cause instanceof CloudHandshakeServiceError) throw cause;
|
|
104
|
+
throw new CloudHandshakeServiceError(
|
|
105
|
+
"Could not load handshake signing keys",
|
|
106
|
+
{ cause }
|
|
107
|
+
);
|
|
53
108
|
});
|
|
54
109
|
return keysPromise;
|
|
55
110
|
}
|
|
@@ -60,5 +115,7 @@ function normalizedCloudUrl() {
|
|
|
60
115
|
return cloudConfig.url.replace(/\/$/, "");
|
|
61
116
|
}
|
|
62
117
|
export {
|
|
118
|
+
CloudHandshakeError,
|
|
119
|
+
CloudHandshakeServiceError,
|
|
63
120
|
verifyCloudHandshake
|
|
64
121
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
package_default
|
|
3
|
-
} from "../chunks/chunk-
|
|
3
|
+
} from "../chunks/chunk-A6M3PNJT.js";
|
|
4
4
|
import "../chunks/chunk-CQ52GEHY.js";
|
|
5
5
|
|
|
6
6
|
// src/cloud/CloudRemote.ts
|
|
@@ -15,12 +15,17 @@ import { HttpError } from "alinea/core/HttpError";
|
|
|
15
15
|
import { ShaMismatchError } from "alinea/core/source/ShaMismatchError";
|
|
16
16
|
import { ReadonlyTree } from "alinea/core/source/Tree";
|
|
17
17
|
import { base64 } from "alinea/core/util/Encoding";
|
|
18
|
-
import { entries
|
|
18
|
+
import { entries } from "alinea/core/util/Objects";
|
|
19
19
|
import { Workspace } from "alinea/core/Workspace";
|
|
20
|
+
import { MediaLocation } from "alinea/core/media/MediaLocation";
|
|
20
21
|
import { Response } from "@alinea/iso";
|
|
21
22
|
import { AuthResultType } from "./AuthResult.js";
|
|
22
23
|
import { cloudConfig } from "./CloudConfig.js";
|
|
23
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
CloudHandshakeError,
|
|
26
|
+
CloudHandshakeServiceError,
|
|
27
|
+
verifyCloudHandshake
|
|
28
|
+
} from "./CloudHandshake.js";
|
|
24
29
|
var CloudRemote = class extends OAuth2 {
|
|
25
30
|
#context;
|
|
26
31
|
#config;
|
|
@@ -125,9 +130,9 @@ var CloudRemote = class extends OAuth2 {
|
|
|
125
130
|
}
|
|
126
131
|
// The cloud server will request a handshake confirmation on this route
|
|
127
132
|
case AuthAction.Handshake: {
|
|
128
|
-
const
|
|
133
|
+
const handshakeId = url.searchParams.get("handshake_id");
|
|
129
134
|
const handshakeToken = url.searchParams.get("handshake_token");
|
|
130
|
-
if (!
|
|
135
|
+
if (!handshakeId || !handshakeToken)
|
|
131
136
|
throw new HttpError(
|
|
132
137
|
400,
|
|
133
138
|
"Provide valid handshake credentials to initiate handshake"
|
|
@@ -138,14 +143,22 @@ var CloudRemote = class extends OAuth2 {
|
|
|
138
143
|
try {
|
|
139
144
|
await verifyCloudHandshake(handshakeToken, {
|
|
140
145
|
clientId,
|
|
141
|
-
handshakeId
|
|
146
|
+
handshakeId,
|
|
142
147
|
origin: new URL(ctx.handlerUrl).origin
|
|
143
148
|
});
|
|
144
149
|
} catch (cause) {
|
|
145
|
-
|
|
150
|
+
if (cause instanceof CloudHandshakeError)
|
|
151
|
+
throw new HttpError(
|
|
152
|
+
401,
|
|
153
|
+
`Invalid handshake token: ${cause.message}`,
|
|
154
|
+
{ cause }
|
|
155
|
+
);
|
|
156
|
+
if (cause instanceof CloudHandshakeServiceError)
|
|
157
|
+
throw new HttpError(503, cause.message, { cause });
|
|
158
|
+
throw new HttpError(500, "Could not verify handshake token", { cause });
|
|
146
159
|
}
|
|
147
160
|
const body = {
|
|
148
|
-
handshake_id:
|
|
161
|
+
handshake_id: handshakeId,
|
|
149
162
|
handshake_token: handshakeToken,
|
|
150
163
|
status: {
|
|
151
164
|
version: package_default.version,
|
|
@@ -157,9 +170,9 @@ var CloudRemote = class extends OAuth2 {
|
|
|
157
170
|
};
|
|
158
171
|
}),
|
|
159
172
|
enableOAuth2: true,
|
|
160
|
-
sourceDirectories:
|
|
161
|
-
const { source
|
|
162
|
-
return [source,
|
|
173
|
+
sourceDirectories: entries(config.workspaces).flatMap(([key, workspace]) => {
|
|
174
|
+
const { source } = Workspace.data(workspace);
|
|
175
|
+
return [source, MediaLocation.directory(config, key)];
|
|
163
176
|
}).filter(Boolean)
|
|
164
177
|
}
|
|
165
178
|
};
|
|
@@ -27,17 +27,17 @@ import {
|
|
|
27
27
|
|
|
28
28
|
// src/components/Calendar.module.css
|
|
29
29
|
var Calendar_default = {
|
|
30
|
+
"Calendar-heading": "alinea-Calendar-heading",
|
|
31
|
+
"CalendarHeading": "alinea-Calendar-heading",
|
|
30
32
|
"Calendar-button": "alinea-Calendar-button",
|
|
31
33
|
"CalendarButton": "alinea-Calendar-button",
|
|
32
34
|
"Calendar-grid": "alinea-Calendar-grid",
|
|
33
35
|
"CalendarGrid": "alinea-Calendar-grid",
|
|
34
|
-
"Calendar-cell": "alinea-Calendar-cell",
|
|
35
|
-
"CalendarCell": "alinea-Calendar-cell",
|
|
36
36
|
"Calendar": "alinea-Calendar",
|
|
37
37
|
"Calendar-header": "alinea-Calendar-header",
|
|
38
38
|
"CalendarHeader": "alinea-Calendar-header",
|
|
39
|
-
"Calendar-
|
|
40
|
-
"
|
|
39
|
+
"Calendar-cell": "alinea-Calendar-cell",
|
|
40
|
+
"CalendarCell": "alinea-Calendar-cell"
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
// src/components/Calendar.tsx
|
|
@@ -16,11 +16,11 @@ import "../chunks/chunk-CQ52GEHY.js";
|
|
|
16
16
|
|
|
17
17
|
// src/components/Checkbox.module.css
|
|
18
18
|
var Checkbox_default = {
|
|
19
|
-
"Checkbox": "alinea-Checkbox",
|
|
19
|
+
"Checkbox-mark": "alinea-Checkbox-mark",
|
|
20
|
+
"CheckboxMark": "alinea-Checkbox-mark",
|
|
20
21
|
"Checkbox-box": "alinea-Checkbox-box",
|
|
21
22
|
"CheckboxBox": "alinea-Checkbox-box",
|
|
22
|
-
"Checkbox
|
|
23
|
-
"CheckboxMark": "alinea-Checkbox-mark"
|
|
23
|
+
"Checkbox": "alinea-Checkbox"
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
// src/components/Checkbox.tsx
|
|
@@ -20,8 +20,8 @@ import { ColorSwatch } from "./ColorSwatch.js";
|
|
|
20
20
|
|
|
21
21
|
// src/components/ColorSwatchPicker.module.css
|
|
22
22
|
var ColorSwatchPicker_default = {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
23
|
+
"ColorSwatchPickerItem": "alinea-ColorSwatchPickerItem",
|
|
24
|
+
"ColorSwatchPicker": "alinea-ColorSwatchPicker"
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
// src/components/ColorSwatchPicker.tsx
|
|
@@ -29,24 +29,24 @@ import {
|
|
|
29
29
|
|
|
30
30
|
// src/components/ComboBox.module.css
|
|
31
31
|
var ComboBox_default = {
|
|
32
|
-
"ComboBoxPopover-listbox": "alinea-ComboBoxPopover-listbox",
|
|
33
|
-
"ComboBoxPopoverListbox": "alinea-ComboBoxPopover-listbox",
|
|
34
32
|
"ComboBoxItem-check": "alinea-ComboBoxItem-check",
|
|
35
33
|
"ComboBoxItemCheck": "alinea-ComboBoxItem-check",
|
|
36
|
-
"ComboBoxTrigger-actions": "alinea-ComboBoxTrigger-actions",
|
|
37
|
-
"ComboBoxTriggerActions": "alinea-ComboBoxTrigger-actions",
|
|
38
34
|
"ComboBox": "alinea-ComboBox",
|
|
39
|
-
"ComboBoxTrigger-button-value": "alinea-ComboBoxTrigger-button-value",
|
|
40
|
-
"ComboBoxTriggerButtonValue": "alinea-ComboBoxTrigger-button-value",
|
|
41
35
|
"ComboBoxTrigger-button-arrow": "alinea-ComboBoxTrigger-button-arrow",
|
|
42
36
|
"ComboBoxTriggerButtonArrow": "alinea-ComboBoxTrigger-button-arrow",
|
|
43
|
-
"ComboBoxTrigger": "alinea-ComboBoxTrigger",
|
|
37
|
+
"ComboBoxTrigger-input": "alinea-ComboBoxTrigger-input",
|
|
38
|
+
"ComboBoxTriggerInput": "alinea-ComboBoxTrigger-input",
|
|
44
39
|
"ComboBoxClear": "alinea-ComboBoxClear",
|
|
45
40
|
"ComboBoxItem": "alinea-ComboBoxItem",
|
|
41
|
+
"ComboBoxTrigger-actions": "alinea-ComboBoxTrigger-actions",
|
|
42
|
+
"ComboBoxTriggerActions": "alinea-ComboBoxTrigger-actions",
|
|
43
|
+
"ComboBoxTrigger-button-value": "alinea-ComboBoxTrigger-button-value",
|
|
44
|
+
"ComboBoxTriggerButtonValue": "alinea-ComboBoxTrigger-button-value",
|
|
45
|
+
"ComboBoxTrigger": "alinea-ComboBoxTrigger",
|
|
46
46
|
"ComboBoxTrigger-button": "alinea-ComboBoxTrigger-button",
|
|
47
47
|
"ComboBoxTriggerButton": "alinea-ComboBoxTrigger-button",
|
|
48
|
-
"
|
|
49
|
-
"
|
|
48
|
+
"ComboBoxPopover-listbox": "alinea-ComboBoxPopover-listbox",
|
|
49
|
+
"ComboBoxPopoverListbox": "alinea-ComboBoxPopover-listbox"
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
// src/components/ComboBox.tsx
|
|
@@ -19,11 +19,11 @@ import "../chunks/chunk-CQ52GEHY.js";
|
|
|
19
19
|
|
|
20
20
|
// src/components/DateField.module.css
|
|
21
21
|
var DateField_default = {
|
|
22
|
-
"DateField-input": "alinea-DateField-input",
|
|
23
|
-
"DateFieldInput": "alinea-DateField-input",
|
|
24
|
-
"DateField": "alinea-DateField",
|
|
25
22
|
"DateField-input-segment": "alinea-DateField-input-segment",
|
|
26
|
-
"DateFieldInputSegment": "alinea-DateField-input-segment"
|
|
23
|
+
"DateFieldInputSegment": "alinea-DateField-input-segment",
|
|
24
|
+
"DateField": "alinea-DateField",
|
|
25
|
+
"DateField-input": "alinea-DateField-input",
|
|
26
|
+
"DateFieldInput": "alinea-DateField-input"
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
// src/components/DateField.tsx
|
|
@@ -25,14 +25,14 @@ import { Calendar } from "./Calendar.js";
|
|
|
25
25
|
|
|
26
26
|
// src/components/DatePicker.module.css
|
|
27
27
|
var DatePicker_default = {
|
|
28
|
-
"DatePicker": "alinea-DatePicker",
|
|
29
28
|
"DatePicker-input": "alinea-DatePicker-input",
|
|
30
29
|
"DatePickerInput": "alinea-DatePicker-input",
|
|
31
30
|
"DatePicker-input-segment": "alinea-DatePicker-input-segment",
|
|
32
31
|
"DatePickerInputSegment": "alinea-DatePicker-input-segment",
|
|
33
|
-
"Icon": "alinea-Icon",
|
|
34
32
|
"DatePicker-trigger": "alinea-DatePicker-trigger",
|
|
35
|
-
"DatePickerTrigger": "alinea-DatePicker-trigger"
|
|
33
|
+
"DatePickerTrigger": "alinea-DatePicker-trigger",
|
|
34
|
+
"Icon": "alinea-Icon",
|
|
35
|
+
"DatePicker": "alinea-DatePicker"
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
// src/components/DatePicker.tsx
|
|
@@ -25,18 +25,18 @@ import { RangeCalendar } from "./Calendar.js";
|
|
|
25
25
|
|
|
26
26
|
// src/components/DateRangePicker.module.css
|
|
27
27
|
var DateRangePicker_default = {
|
|
28
|
-
"DateRangePicker-input-segment": "alinea-DateRangePicker-input-segment",
|
|
29
|
-
"DateRangePickerInputSegment": "alinea-DateRangePicker-input-segment",
|
|
30
|
-
"DateRangePicker-trigger": "alinea-DateRangePicker-trigger",
|
|
31
|
-
"DateRangePickerTrigger": "alinea-DateRangePicker-trigger",
|
|
32
|
-
"DateRangePicker-inputs": "alinea-DateRangePicker-inputs",
|
|
33
|
-
"DateRangePickerInputs": "alinea-DateRangePicker-inputs",
|
|
34
28
|
"DateRangePicker-input": "alinea-DateRangePicker-input",
|
|
35
29
|
"DateRangePickerInput": "alinea-DateRangePicker-input",
|
|
30
|
+
"DateRangePicker-inputs": "alinea-DateRangePicker-inputs",
|
|
31
|
+
"DateRangePickerInputs": "alinea-DateRangePicker-inputs",
|
|
36
32
|
"DateRangePicker-separator": "alinea-DateRangePicker-separator",
|
|
37
33
|
"DateRangePickerSeparator": "alinea-DateRangePicker-separator",
|
|
38
|
-
"
|
|
39
|
-
"DateRangePicker": "alinea-DateRangePicker"
|
|
34
|
+
"DateRangePicker": "alinea-DateRangePicker",
|
|
35
|
+
"DateRangePicker-trigger": "alinea-DateRangePicker-trigger",
|
|
36
|
+
"DateRangePickerTrigger": "alinea-DateRangePicker-trigger",
|
|
37
|
+
"DateRangePicker-input-segment": "alinea-DateRangePicker-input-segment",
|
|
38
|
+
"DateRangePickerInputSegment": "alinea-DateRangePicker-input-segment",
|
|
39
|
+
"Icon": "alinea-Icon"
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
// src/components/DateRangePicker.tsx
|
|
@@ -25,17 +25,17 @@ import { Icon } from "./Icon.js";
|
|
|
25
25
|
var Disclosure_default = {
|
|
26
26
|
"Disclosure-panel-content": "alinea-Disclosure-panel-content",
|
|
27
27
|
"DisclosurePanelContent": "alinea-Disclosure-panel-content",
|
|
28
|
+
"Disclosure-chevron": "alinea-Disclosure-chevron",
|
|
29
|
+
"DisclosureChevron": "alinea-Disclosure-chevron",
|
|
30
|
+
"Disclosure-heading": "alinea-Disclosure-heading",
|
|
31
|
+
"DisclosureHeading": "alinea-Disclosure-heading",
|
|
28
32
|
"Disclosure-title": "alinea-Disclosure-title",
|
|
29
33
|
"DisclosureTitle": "alinea-Disclosure-title",
|
|
30
|
-
"Disclosure
|
|
31
|
-
"DisclosurePanel": "alinea-Disclosure-panel",
|
|
34
|
+
"Disclosure": "alinea-Disclosure",
|
|
32
35
|
"Disclosure-trigger": "alinea-Disclosure-trigger",
|
|
33
36
|
"DisclosureTrigger": "alinea-Disclosure-trigger",
|
|
34
|
-
"Disclosure": "alinea-Disclosure",
|
|
35
|
-
"
|
|
36
|
-
"DisclosureHeading": "alinea-Disclosure-heading",
|
|
37
|
-
"Disclosure-chevron": "alinea-Disclosure-chevron",
|
|
38
|
-
"DisclosureChevron": "alinea-Disclosure-chevron"
|
|
37
|
+
"Disclosure-panel": "alinea-Disclosure-panel",
|
|
38
|
+
"DisclosurePanel": "alinea-Disclosure-panel"
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
// src/components/Disclosure.tsx
|