@weasel-js/forge 1.13.0 → 1.14.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/README.md +1 -1
- package/dist/{FrameController-DgfVaENb.d.ts → FrameController-BM6xuEfY.d.ts} +6 -10
- package/dist/{chunk-7XJNVJB5.js → chunk-B26DWEYT.js} +3 -3
- package/dist/{chunk-7XJNVJB5.js.map → chunk-B26DWEYT.js.map} +1 -1
- package/dist/{chunk-3BAM6M26.js → chunk-FPF2JSWB.js} +3 -3
- package/dist/chunk-FPF2JSWB.js.map +1 -0
- package/dist/{chunk-ORMMZ5PV.js → chunk-MRYXJTDO.js} +7 -3
- package/dist/chunk-MRYXJTDO.js.map +1 -0
- package/dist/{chunk-GHPMNT2A.js → chunk-PGLOYXDP.js} +184 -184
- package/dist/chunk-PGLOYXDP.js.map +1 -0
- package/dist/{chunk-WFT5IOHX.js → chunk-PPB7VP6R.js} +5 -4
- package/dist/chunk-PPB7VP6R.js.map +1 -0
- package/dist/{chunk-COT4I347.js → chunk-SFKDHXVE.js} +26 -4
- package/dist/chunk-SFKDHXVE.js.map +1 -0
- package/dist/chunk-STK2AZH2.js +11 -0
- package/dist/chunk-STK2AZH2.js.map +1 -0
- package/dist/chunk-TT4ZOYB6.js +143 -0
- package/dist/chunk-TT4ZOYB6.js.map +1 -0
- package/dist/{chunk-XIBKYSRU.js → chunk-UDEUT7AG.js} +124 -80
- package/dist/chunk-UDEUT7AG.js.map +1 -0
- package/dist/{config-6fWf87Tt.d.ts → config-DOjWyIui.d.ts} +1 -1
- package/dist/csf/preview-api.js +2 -2
- package/dist/frame/index.css +0 -2
- package/dist/frame/index.css.map +1 -1
- package/dist/frame/index.d.ts +4 -4
- package/dist/frame/index.js +9 -6
- package/dist/frame/index.js.map +1 -1
- package/dist/index.d.ts +11 -5
- package/dist/index.js +4 -4
- package/dist/{mountFrame-Bs7u1ro-.d.ts → mountFrame-CRPAjg1M.d.ts} +1 -1
- package/dist/shell/index.css +164 -147
- package/dist/shell/index.css.map +1 -1
- package/dist/shell/index.d.ts +23 -5
- package/dist/shell/index.js +454 -318
- package/dist/shell/index.js.map +1 -1
- package/dist/test/index.d.ts +1 -1
- package/dist/test/index.js +8 -10
- package/dist/test/index.js.map +1 -1
- package/dist/vite/index.js +118 -30
- package/dist/vite/index.js.map +1 -1
- package/package.json +11 -9
- package/dist/chunk-2ZBZRBHI.js +0 -10
- package/dist/chunk-2ZBZRBHI.js.map +0 -1
- package/dist/chunk-3BAM6M26.js.map +0 -1
- package/dist/chunk-COT4I347.js.map +0 -1
- package/dist/chunk-GHPMNT2A.js.map +0 -1
- package/dist/chunk-L5XM5VKB.js +0 -47
- package/dist/chunk-L5XM5VKB.js.map +0 -1
- package/dist/chunk-ORMMZ5PV.js.map +0 -1
- package/dist/chunk-WFT5IOHX.js.map +0 -1
- package/dist/chunk-XIBKYSRU.js.map +0 -1
package/dist/test/index.d.ts
CHANGED
package/dist/test/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { StoryTrial } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
3
|
-
import { loadStories } from '../chunk-
|
|
4
|
-
import '../chunk-
|
|
1
|
+
import { StoryTrial } from '../chunk-UDEUT7AG.js';
|
|
2
|
+
import '../chunk-FPF2JSWB.js';
|
|
3
|
+
import { loadStories } from '../chunk-PGLOYXDP.js';
|
|
4
|
+
import '../chunk-TT4ZOYB6.js';
|
|
5
5
|
import '../chunk-5WS67HMU.js';
|
|
6
|
-
import '../chunk-
|
|
7
|
-
import '../chunk-
|
|
6
|
+
import '../chunk-B26DWEYT.js';
|
|
7
|
+
import '../chunk-STK2AZH2.js';
|
|
8
8
|
import { withValueAtPath } from '@weasel-js/labkit/config';
|
|
9
9
|
import { useState, useEffect } from 'react';
|
|
10
10
|
import { createRoot } from 'react-dom/client';
|
|
@@ -42,10 +42,8 @@ async function runStory(mod, exportName, file, title, { setup = {} } = {}) {
|
|
|
42
42
|
}
|
|
43
43
|
if (!story) throw new Error(`load fault: ${file} has no story export "${exportName}"`);
|
|
44
44
|
const container = document.createElement("div");
|
|
45
|
-
if (story.viewport) {
|
|
46
|
-
|
|
47
|
-
container.style.height = `${story.viewport.height}px`;
|
|
48
|
-
}
|
|
45
|
+
if (story.viewport) container.style.width = `${story.viewport.width}px`;
|
|
46
|
+
container.style.height = story.viewport ? `${story.viewport.height}px` : "100vh";
|
|
49
47
|
document.body.append(container);
|
|
50
48
|
let root;
|
|
51
49
|
const cleanup = () => {
|
package/dist/test/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/test/runStory.tsx"],"names":[],"mappings":";;;;;;;;;;;;AASA,SAAS,MAAA,CAAO,OAAe,KAAA,EAAuB;AACpD,EAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,EAAA,MAAM,GAAA,GAAM,IAAI,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,QAAA,EAAW,OAAO,CAAA,CAAA,EAAI,EAAE,KAAA,EAAO,KAAA,EAAO,CAAA;AACpE,EAAA,IAAI,KAAA,YAAiB,KAAA,IAAS,KAAA,CAAM,KAAA,EAAO,GAAA,CAAI,QAAQ,CAAA,EAAG,KAAK,CAAA,QAAA,EAAW,KAAA,CAAM,KAAK,CAAA,CAAA;AACrF,EAAA,OAAO,GAAA;AACT;AAEA,IAAM,MAAA,GAAS,MACb,IAAI,OAAA,CAAc,CAAC,OAAA,KAAY;AAC7B,EAAA,qBAAA,CAAsB,MAAM,UAAA,CAAW,OAAA,EAAS,CAAC,CAAC,CAAA;AACpD,CAAC,CAAA;AAaH,SAAS,SAAA,CAAU,EAAE,KAAA,EAAO,KAAA,EAAO,SAAS,QAAA,EAAU,UAAA,EAAY,SAAQ,EAAmB;AAC3F,EAAA,MAAM,CAAC,QAAQ,cAAc,CAAA,GAAI,SAAkB,MAAM,KAAA,CAAM,MAAA,CAAO,QAAA,EAAU,CAAA;AAChF,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAkB,IAAI,CAAA;AAChD,EAAA,SAAA,CAAU,MAAM,QAAA,CAAS,MAAM,GAAG,CAAC,MAAA,EAAQ,QAAQ,CAAC,CAAA;AACpD,EAAA,MAAM,GAAA,GAAM;AAAA,IACV,MAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA,EAAW,CAAC,IAAA,EAAc,KAAA,KAAmB,cAAA,CAAe,CAAC,IAAA,KAAkB,eAAA,CAAgB,IAAA,EAAM,IAAA,EAAM,KAAK,CAAC,CAAA;AAAA,IACjH;AAAA,GACF;AACA,EAAA,2BAAQ,UAAA,EAAA,EAAW,KAAA,EAAc,OAAc,GAAA,EAAU,OAAA,EAAkB,YAAwB,OAAA,EAAkB,CAAA;AACvH;AASA,IAAI,QAAA,GAAmC,IAAA;AAMvC,eAAsB,QAAA,CACpB,GAAA,EACA,UAAA,EACA,IAAA,EAEA,KAAA,EACA,EAAE,KAAA,GAAQ,EAAC,EAAE,GAAqB,EAAC,EACpB;AACf,EAAA,QAAA,IAAW;AACX,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,KAAA,GAAQ,WAAA,CAAY,GAAA,EAAK,KAAA,EAAO,KAAA,CAAM,UAAU,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,KAAe,UAAU,CAAA;AAAA,EAC3F,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,MAAA,CAAO,QAAQ,KAAK,CAAA;AAAA,EAC5B;AACA,EAAA,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,CAAA,YAAA,EAAe,IAAI,CAAA,sBAAA,EAAyB,UAAU,CAAA,CAAA,CAAG,CAAA;AAErF,EAAA,MAAM,SAAA,GAAY,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAE9C,EAAA,IAAI,
|
|
1
|
+
{"version":3,"sources":["../../src/test/runStory.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { withValueAtPath } from '@weasel-js/labkit/config';\nimport { type RefObject, useEffect, useState } from 'react';\nimport { createRoot, type Root } from 'react-dom/client';\nimport type { FrameSetup } from '../frame/FrameController';\nimport { StoryTrial } from '../shell/StoryTrial';\nimport { loadStories } from '../story/load';\nimport type { LoadedStory } from '../story/types';\n\n/** Prefixes `error` with the phase it came from, keeping its stack. */\nfunction phased(phase: string, error: unknown): Error {\n const message = error instanceof Error ? error.message : String(error);\n const out = new Error(`${phase} fault: ${message}`, { cause: error });\n if (error instanceof Error && error.stack) out.stack = `${phase} fault: ${error.stack}`;\n return out;\n}\n\nconst settle = () =>\n new Promise<void>((resolve) => {\n requestAnimationFrame(() => setTimeout(resolve, 0));\n });\n\ninterface TestTrialProps {\n story: LoadedStory;\n setup: FrameSetup;\n hostRef: RefObject<HTMLElement | null>;\n /** The config in force after each commit, so `play` reads what the story last wrote. */\n onConfig: (config: unknown) => void;\n onRendered: () => void;\n onError: (error: unknown) => void;\n}\n\n/** The trial a story test runs in: its config and state, held the way a lab trial holds them. */\nfunction TestTrial({ story, setup, hostRef, onConfig, onRendered, onError }: TestTrialProps) {\n const [config, setConfigState] = useState<unknown>(() => story.config.defaults());\n const [state, setState] = useState<unknown>(null);\n useEffect(() => onConfig(config), [config, onConfig]);\n const ctx = {\n config,\n state,\n setConfig: (path: string, value: unknown) => setConfigState((prev: unknown) => withValueAtPath(prev, path, value)),\n setState,\n };\n return <StoryTrial story={story} setup={setup} ctx={ctx} hostRef={hostRef} onRendered={onRendered} onError={onError} />;\n}\n\n/** Options for `runStory`. */\nexport interface RunStoryOptions {\n /** The frame config (`frameConfig`). */\n setup?: FrameSetup;\n}\n\n/** Stops the story a timed-out test left mounted. */\nlet leftover: (() => unknown) | null = null;\n\n/**\n * Renders one story in the test page the way the workshop does — defaults, no state, no globals — then plays it.\n * Throws on a render the story's boundary caught, or a play function that fails.\n */\nexport async function runStory(\n mod: Record<string, unknown>,\n exportName: string,\n file: string,\n /** The file's index entry title. */\n title: string,\n { setup = {} }: RunStoryOptions = {},\n): Promise<void> {\n leftover?.();\n let story: LoadedStory | undefined;\n try {\n story = loadStories(mod, title, setup.parameters).find((s) => s.exportName === exportName);\n } catch (error) {\n throw phased('load', error);\n }\n if (!story) throw new Error(`load fault: ${file} has no story export \"${exportName}\"`);\n\n const container = document.createElement('div');\n // The workshop gives a story's viewport to its stage, a box of that size, not to the window.\n if (story.viewport) container.style.width = `${story.viewport.width}px`;\n // Without one the stage still fills the workshop's preview: an auto height lays a filling story out 0 tall.\n container.style.height = story.viewport ? `${story.viewport.height}px` : '100vh';\n document.body.append(container);\n let root: Root | undefined;\n /** Returns what unmounting threw, having released everything else regardless. */\n const cleanup = (): { error: unknown } | null => {\n if (leftover === cleanup) leftover = null;\n let thrown: { error: unknown } | null = null;\n try {\n root?.unmount();\n } catch (error) {\n thrown = { error };\n } finally {\n root = undefined;\n container.remove();\n }\n return thrown;\n };\n leftover = cleanup;\n\n const hostRef: RefObject<HTMLElement | null> = { current: null };\n let config: unknown;\n let renderError: { error: unknown } | null = null;\n let markRendered: () => void = () => {};\n const rendered = new Promise<void>((resolve) => {\n markRendered = resolve;\n });\n const fail = (error: unknown) => {\n renderError ??= { error };\n // An error the boundary could not catch leaves nothing to announce `rendered`; the check below throws instead.\n markRendered();\n };\n const checkRender = () => {\n if (renderError) throw phased('render', renderError.error);\n };\n\n let failure: { error: unknown } | null = null;\n try {\n try {\n await setup.prepare?.(story);\n root = createRoot(container, { onUncaughtError: fail });\n root.render(\n <TestTrial\n story={story}\n setup={setup}\n hostRef={hostRef}\n onConfig={(next) => {\n config = next;\n }}\n onRendered={markRendered}\n onError={fail}\n />,\n );\n } catch (error) {\n throw phased('mount', error);\n }\n await rendered;\n await settle();\n checkRender();\n const host = hostRef.current;\n if (!host) throw new Error('render fault: the story host never mounted');\n if (story.play) {\n try {\n await story.play({ canvasElement: host, config, globals: {} });\n } catch (error) {\n throw phased('play', error);\n }\n await settle();\n checkRender();\n }\n } catch (error) {\n failure = { error };\n }\n const cleanupError = cleanup();\n if (failure) throw failure.error;\n if (cleanupError) throw phased('cleanup', cleanupError.error);\n}\n"]}
|
package/dist/vite/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { CAPTURE_PAGES, DEFAULT_TITLE, CAPTURE_PATH, parsePayload, messageOf } from '../chunk-
|
|
1
|
+
import { CAPTURE_PAGES, DEFAULT_TITLE, ISSUES_PATH, CAPTURE_PATH, issueLabel, parsePayload, messageOf } from '../chunk-MRYXJTDO.js';
|
|
2
2
|
import { byComponent } from '../chunk-RVJHUY7W.js';
|
|
3
3
|
import { isGallery } from '../chunk-VUPN73JP.js';
|
|
4
4
|
import { PROP_ARG_TYPES_EXPORT, storyNameFromExport, storyId } from '../chunk-5WS67HMU.js';
|
|
5
5
|
import { readFileSync, mkdtempSync, existsSync, mkdirSync, writeFileSync, globSync, statSync, watch, rmSync } from 'fs';
|
|
6
|
-
import { resolve,
|
|
6
|
+
import { resolve, relative, sep, join, dirname, basename, matchesGlob, posix } from 'path';
|
|
7
7
|
import { parse } from '@babel/parser';
|
|
8
8
|
import { execFile } from 'child_process';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
@@ -1048,7 +1048,7 @@ function controlFor(reading, type, written) {
|
|
|
1048
1048
|
const { TypeFlags } = reading.tsm;
|
|
1049
1049
|
const parts = type.isUnion() ? type.types : [type];
|
|
1050
1050
|
if (parts.every((part) => part.flags & TypeFlags.BooleanLike)) return { control: { type: "boolean" } };
|
|
1051
|
-
if (
|
|
1051
|
+
if (textLike(reading, parts)) return { control: { type: "text" } };
|
|
1052
1052
|
if (type.flags & TypeFlags.Number) return { control: { type: "number" } };
|
|
1053
1053
|
const options = literalsOf(reading, parts);
|
|
1054
1054
|
if (options.length > 1) {
|
|
@@ -1060,6 +1060,9 @@ function controlFor(reading, type, written) {
|
|
|
1060
1060
|
return shape && shape.name !== "enum" && !(shape.name in SCALARS) ? { control: "object", type: shape } : null;
|
|
1061
1061
|
}
|
|
1062
1062
|
var SCALARS = { boolean: true, string: true, number: true };
|
|
1063
|
+
function textLike({ tsm }, parts) {
|
|
1064
|
+
return parts.some((part) => part.flags & tsm.TypeFlags.String) && !parts.some((part) => part.flags & tsm.TypeFlags.Object);
|
|
1065
|
+
}
|
|
1063
1066
|
function literalsOf({ tsm }, parts) {
|
|
1064
1067
|
return parts.filter((part) => part.flags & tsm.TypeFlags.StringLiteral).map((part) => part.value);
|
|
1065
1068
|
}
|
|
@@ -1072,7 +1075,7 @@ function shapeOf(reading, type, depth) {
|
|
|
1072
1075
|
const parts = whole.isUnion() ? whole.types : [whole];
|
|
1073
1076
|
if (parts.length === 0) return null;
|
|
1074
1077
|
if (parts.every((part) => part.flags & TypeFlags.BooleanLike)) return { name: "boolean" };
|
|
1075
|
-
if (
|
|
1078
|
+
if (textLike(reading, parts)) return { name: "string" };
|
|
1076
1079
|
if (whole.flags & TypeFlags.Number) return { name: "number" };
|
|
1077
1080
|
const literals = literalsOf(reading, parts);
|
|
1078
1081
|
if (literals.length === parts.length || literals.length > 1) return { name: "enum", value: literals };
|
|
@@ -1166,6 +1169,86 @@ export const ${PROP_ARG_TYPES_EXPORT} = ${JSON.stringify(table.argTypes)};
|
|
|
1166
1169
|
}
|
|
1167
1170
|
};
|
|
1168
1171
|
}
|
|
1172
|
+
var runGh = (args, cwd) => new Promise((done) => {
|
|
1173
|
+
execFile(
|
|
1174
|
+
"gh",
|
|
1175
|
+
[...args],
|
|
1176
|
+
{ cwd, maxBuffer: 16 << 20, env: { ...process.env, GH_PROMPT_DISABLED: "1" } },
|
|
1177
|
+
(error, stdout, stderr) => {
|
|
1178
|
+
if (!error) return done({ stdout });
|
|
1179
|
+
if (error.code === "ENOENT") return done({ missing: true });
|
|
1180
|
+
done({ failed: stderr.trim() || error.message, code: typeof error.code === "number" ? error.code : null });
|
|
1181
|
+
}
|
|
1182
|
+
);
|
|
1183
|
+
});
|
|
1184
|
+
var SCP = /^(?:[^@\s/]+@)?([\w.-]+):(?!\/)([\w.-]+)\/([\w.-]+?)(?:\.git)?\/?$/;
|
|
1185
|
+
var URL_FORM = /^(?:ssh|git|https?):\/\/(?:[^@/\s]+@)?([\w.-]+)(?::\d+)?\/([\w.-]+)\/([\w.-]+?)(?:\.git)?\/?$/;
|
|
1186
|
+
function repoOf(remote) {
|
|
1187
|
+
const match = SCP.exec(remote.trim()) ?? URL_FORM.exec(remote.trim());
|
|
1188
|
+
if (!match) return null;
|
|
1189
|
+
const [, rawHost = "", owner = "", name = ""] = match;
|
|
1190
|
+
const host = rawHost === "github.com" || rawHost.endsWith(".github.com") ? "github.com" : rawHost;
|
|
1191
|
+
const slug = `${owner}/${name}`;
|
|
1192
|
+
return { slug, url: `https://${host}/${slug}`, ghRepo: host === "github.com" ? slug : `${host}/${slug}` };
|
|
1193
|
+
}
|
|
1194
|
+
var attempt = async (run) => {
|
|
1195
|
+
try {
|
|
1196
|
+
return (await run()).trim() || null;
|
|
1197
|
+
} catch {
|
|
1198
|
+
return null;
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
var GH_AUTH_EXIT = 4;
|
|
1202
|
+
var json = (res, status, body2) => {
|
|
1203
|
+
res.statusCode = status;
|
|
1204
|
+
res.setHeader("Content-Type", "application/json");
|
|
1205
|
+
res.end(JSON.stringify(body2));
|
|
1206
|
+
};
|
|
1207
|
+
function serveIssues(server, base, root, { gh = runGh, git = runGit } = {}) {
|
|
1208
|
+
const answer = async (component) => {
|
|
1209
|
+
const cwd = root();
|
|
1210
|
+
const [remote, head, commit] = await Promise.all([
|
|
1211
|
+
attempt(() => git(["remote", "get-url", "origin"], cwd)),
|
|
1212
|
+
attempt(() => git(["rev-parse", "--abbrev-ref", "HEAD"], cwd)),
|
|
1213
|
+
attempt(() => git(["rev-parse", "HEAD"], cwd))
|
|
1214
|
+
]);
|
|
1215
|
+
const found = remote === null ? null : repoOf(remote);
|
|
1216
|
+
const context = {
|
|
1217
|
+
repo: found && { slug: found.slug, url: found.url },
|
|
1218
|
+
branch: head === "HEAD" ? null : head,
|
|
1219
|
+
commit
|
|
1220
|
+
};
|
|
1221
|
+
if (!found) return { status: 200, body: { ...context, unavailable: "This checkout\u2019s origin is not a GitHub repository." } };
|
|
1222
|
+
const fields = "number,title,url,createdAt";
|
|
1223
|
+
const result = await gh(
|
|
1224
|
+
["issue", "list", "-R", found.ghRepo, "--label", issueLabel(component), "--state", "open", "--json", fields],
|
|
1225
|
+
cwd
|
|
1226
|
+
);
|
|
1227
|
+
if ("missing" in result) return { status: 200, body: { ...context, unavailable: "The GitHub CLI (gh) is not installed." } };
|
|
1228
|
+
if ("failed" in result) {
|
|
1229
|
+
if (result.code === GH_AUTH_EXIT || /gh auth login/.test(result.failed)) {
|
|
1230
|
+
return { status: 200, body: { ...context, unavailable: "The GitHub CLI (gh) is not logged in. Run gh auth login." } };
|
|
1231
|
+
}
|
|
1232
|
+
return { status: 502, body: { ...context, error: result.failed } };
|
|
1233
|
+
}
|
|
1234
|
+
let listed;
|
|
1235
|
+
try {
|
|
1236
|
+
listed = JSON.parse(result.stdout);
|
|
1237
|
+
} catch {
|
|
1238
|
+
return { status: 502, body: { ...context, error: "gh answered something that is not JSON" } };
|
|
1239
|
+
}
|
|
1240
|
+
const issues = listed.map(({ number, title, url, createdAt }) => ({ number, title, url, opened: createdAt }));
|
|
1241
|
+
return { status: 200, body: { ...context, issues } };
|
|
1242
|
+
};
|
|
1243
|
+
server.middlewares.use((req, res, next) => {
|
|
1244
|
+
const url = new URL(req.url ?? "/", "http://forge.invalid");
|
|
1245
|
+
if (url.pathname !== `${base}${ISSUES_PATH}`) return next();
|
|
1246
|
+
if (req.method !== "GET") return next();
|
|
1247
|
+
const component = url.searchParams.get("component")?.trim();
|
|
1248
|
+
if (!component) return json(res, 400, { error: "name a component: ?component=<name>" });
|
|
1249
|
+
answer(component).then(({ status, body: body2 }) => json(res, status, body2), next);
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1169
1252
|
var IDLE_CLOSE_MS = 12e4;
|
|
1170
1253
|
var SHOT_DEADLINE_MS = 2e4;
|
|
1171
1254
|
var QUEUE_CAP = 8;
|
|
@@ -1388,7 +1471,7 @@ function ownOrigin(origin, req, protocol, server) {
|
|
|
1388
1471
|
const printed = [...server.resolvedUrls?.local ?? [], ...server.resolvedUrls?.network ?? []];
|
|
1389
1472
|
return printed.some((u) => new URL(u).origin === url.origin);
|
|
1390
1473
|
}
|
|
1391
|
-
var
|
|
1474
|
+
var json2 = (res, status, body2) => {
|
|
1392
1475
|
res.statusCode = status;
|
|
1393
1476
|
res.setHeader("Content-Type", "application/json");
|
|
1394
1477
|
res.end(JSON.stringify(body2));
|
|
@@ -1426,37 +1509,37 @@ function serveCapture(server, base, allowOrigins = () => []) {
|
|
|
1426
1509
|
const capture = async (req, res) => {
|
|
1427
1510
|
const origin = req.headers.origin;
|
|
1428
1511
|
if (origin !== void 0 && !ownOrigin(origin, req, protocol, server)) {
|
|
1429
|
-
return
|
|
1512
|
+
return json2(res, 403, { error: "a capture is only taken for this server\u2019s own pages" });
|
|
1430
1513
|
}
|
|
1431
1514
|
const type = (req.headers["content-type"] ?? "").split(";")[0]?.trim().toLowerCase();
|
|
1432
|
-
if (type !== "application/json") return
|
|
1515
|
+
if (type !== "application/json") return json2(res, 415, { error: "a capture payload is sent as application/json" });
|
|
1433
1516
|
const body2 = await readBody(req);
|
|
1434
1517
|
if (body2 === null) {
|
|
1435
1518
|
res.setHeader("Connection", "close");
|
|
1436
|
-
|
|
1519
|
+
json2(res, 413, { error: "capture payload is too large" });
|
|
1437
1520
|
return void res.once("finish", () => req.destroy());
|
|
1438
1521
|
}
|
|
1439
1522
|
let parsed;
|
|
1440
1523
|
try {
|
|
1441
1524
|
parsed = JSON.parse(body2);
|
|
1442
1525
|
} catch {
|
|
1443
|
-
return
|
|
1526
|
+
return json2(res, 400, { error: "capture payload is not JSON" });
|
|
1444
1527
|
}
|
|
1445
1528
|
const payload = parsePayload(parsed);
|
|
1446
|
-
if ("error" in payload) return
|
|
1529
|
+
if ("error" in payload) return json2(res, 400, payload);
|
|
1447
1530
|
const key = keyOf2(payload);
|
|
1448
1531
|
let png = cache.get(key);
|
|
1449
1532
|
if (!png) {
|
|
1450
1533
|
const result = await browser();
|
|
1451
|
-
if ("unavailable" in result) return
|
|
1534
|
+
if ("unavailable" in result) return json2(res, 503, { available: false, reason: result.unavailable });
|
|
1452
1535
|
const page = `${socketOrigin(req, protocol)}${base}${payload.isolate ? CAPTURE_PAGES.frame : CAPTURE_PAGES.shell}`;
|
|
1453
1536
|
const at = revision;
|
|
1454
1537
|
try {
|
|
1455
1538
|
png = await result.capture(page, payload, allowOrigins());
|
|
1456
1539
|
} catch (err) {
|
|
1457
1540
|
const message = messageOf(err);
|
|
1458
|
-
if (message === QUEUE_FULL) return
|
|
1459
|
-
return
|
|
1541
|
+
if (message === QUEUE_FULL) return json2(res, 503, { available: false, reason: QUEUE_FULL });
|
|
1542
|
+
return json2(res, 500, { error: message });
|
|
1460
1543
|
}
|
|
1461
1544
|
if (at === revision) cache.set(key, png);
|
|
1462
1545
|
}
|
|
@@ -1466,7 +1549,7 @@ function serveCapture(server, base, allowOrigins = () => []) {
|
|
|
1466
1549
|
};
|
|
1467
1550
|
const status = async (res) => {
|
|
1468
1551
|
const result = await captureAvailability();
|
|
1469
|
-
|
|
1552
|
+
json2(res, 200, "unavailable" in result ? { available: false, reason: result.unavailable } : { available: true });
|
|
1470
1553
|
};
|
|
1471
1554
|
server.middlewares.use((req, res, next) => {
|
|
1472
1555
|
if (req.url?.split("?")[0] !== `${base}${CAPTURE_PATH}`) return next();
|
|
@@ -1641,6 +1724,7 @@ const workshop = mountWorkshop({
|
|
|
1641
1724
|
config,
|
|
1642
1725
|
frameUrl: ${JSON.stringify(`${base}frame.html`)},
|
|
1643
1726
|
captureBase: ${JSON.stringify(base)},
|
|
1727
|
+
issuesBase: ${JSON.stringify(base)},
|
|
1644
1728
|
stories: ${JSON.stringify(stories)},
|
|
1645
1729
|
});
|
|
1646
1730
|
// Read from source on first request, so the graph costs nothing until the page is up.
|
|
@@ -1757,6 +1841,21 @@ function watchProbe({ probe } = {}) {
|
|
|
1757
1841
|
|
|
1758
1842
|
// src/vite/plugin.ts
|
|
1759
1843
|
var SCRIPT2 = /\.[cm]?[jt]sx?$/;
|
|
1844
|
+
function watchSources(server, { files, depGraph, reindex, redeps, logError }) {
|
|
1845
|
+
server.watcher.add([...files]);
|
|
1846
|
+
void warnWhenWatchIsSilent(server);
|
|
1847
|
+
for (const event of ["add", "change", "unlink"]) {
|
|
1848
|
+
server.watcher.on(event, (path) => {
|
|
1849
|
+
const file = resolve(path);
|
|
1850
|
+
const added = event === "add" && SCRIPT2.test(file) && !file.split(sep).includes("node_modules");
|
|
1851
|
+
if (added) depGraph().reset();
|
|
1852
|
+
const read = added || event !== "add" && depGraph().invalidate(file);
|
|
1853
|
+
reindex(server, file, event).then((indexed) => {
|
|
1854
|
+
if (indexed || read) redeps(server);
|
|
1855
|
+
}, logError);
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1760
1859
|
function forge(options) {
|
|
1761
1860
|
let root = process.cwd();
|
|
1762
1861
|
let base = "/";
|
|
@@ -1842,9 +1941,9 @@ function forge(options) {
|
|
|
1842
1941
|
const resolve6 = async (spec, importer) => (await server.environments.client.pluginContainer.resolveId(spec, importer))?.id ?? null;
|
|
1843
1942
|
depsPending = Promise.resolve().then(async () => {
|
|
1844
1943
|
const graph = await graphOf(resolve6);
|
|
1845
|
-
const
|
|
1846
|
-
if (
|
|
1847
|
-
depsSent =
|
|
1944
|
+
const json3 = JSON.stringify(graph);
|
|
1945
|
+
if (json3 === depsSent) return;
|
|
1946
|
+
depsSent = json3;
|
|
1848
1947
|
invalidate(server, ["deps.js"]);
|
|
1849
1948
|
server.ws.send({ type: "custom", event: "forge:deps", data: graph });
|
|
1850
1949
|
}).catch(logError).finally(() => {
|
|
@@ -1949,20 +2048,9 @@ function forge(options) {
|
|
|
1949
2048
|
for (const file of storiesReaching(modules2)) server.ws.send({ type: "custom", event: "forge:story", data: { file } });
|
|
1950
2049
|
},
|
|
1951
2050
|
configureServer(server) {
|
|
1952
|
-
server
|
|
1953
|
-
void warnWhenWatchIsSilent(server);
|
|
1954
|
-
for (const event of ["add", "change", "unlink"]) {
|
|
1955
|
-
server.watcher.on(event, (path) => {
|
|
1956
|
-
const file = resolve(path);
|
|
1957
|
-
const added = event === "add" && SCRIPT2.test(file) && !file.split(sep).includes("node_modules");
|
|
1958
|
-
if (added) depGraph().reset();
|
|
1959
|
-
const read2 = added || event !== "add" && depGraph().invalidate(file);
|
|
1960
|
-
reindex(server, file, event).then((indexed) => {
|
|
1961
|
-
if (indexed || read2) redeps(server);
|
|
1962
|
-
}, logError);
|
|
1963
|
-
});
|
|
1964
|
-
}
|
|
2051
|
+
watchSources(server, { files: [...files().keys()], depGraph, reindex, redeps, logError });
|
|
1965
2052
|
capture = servePages(server, base, () => shellUnder(root));
|
|
2053
|
+
serveIssues(server, base, () => root);
|
|
1966
2054
|
},
|
|
1967
2055
|
closeServer: () => capture?.close()
|
|
1968
2056
|
}
|