@weasel-js/forge 1.16.2 → 1.17.1
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/{chunk-SFKDHXVE.js → chunk-MUBZSDOI.js} +4 -4
- package/dist/chunk-MUBZSDOI.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/shell/index.js +1 -1
- package/dist/vite/index.js +56 -25
- package/dist/vite/index.js.map +1 -1
- package/package.json +14 -17
- package/dist/chunk-SFKDHXVE.js.map +0 -1
|
@@ -110,7 +110,7 @@ function knobPaths(schema) {
|
|
|
110
110
|
if (key.startsWith(INTERNAL_PREFIX) || key.includes(".")) continue;
|
|
111
111
|
const path = at === "" ? key : `${at}.${key}`;
|
|
112
112
|
if (isConfigBranch(entry)) walk(entry.children, path);
|
|
113
|
-
else if (codecOf(entry) !== null) out.push({ path, leaf: entry });
|
|
113
|
+
else if (codecOf(entry) !== null && isKnobParam(path)) out.push({ path, leaf: entry });
|
|
114
114
|
}
|
|
115
115
|
};
|
|
116
116
|
walk(schema.nodes, "");
|
|
@@ -133,7 +133,7 @@ function paramsToKnobs(schema, params) {
|
|
|
133
133
|
const knobs = {};
|
|
134
134
|
for (const { path, leaf } of knobPaths(schema)) {
|
|
135
135
|
const raw = params[path];
|
|
136
|
-
if (raw === void 0
|
|
136
|
+
if (raw === void 0) continue;
|
|
137
137
|
const decoded = decodeKnob(raw, leaf);
|
|
138
138
|
if (decoded) knobs[path] = decoded.value;
|
|
139
139
|
}
|
|
@@ -170,5 +170,5 @@ function paramsToPins(schema, params) {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
export { PLAYHEAD_PARAM, RESERVED_PARAMS, decodeKnob, encodeKnob, formatRoute, knobParams, knobPaths, knobsToParams, paramsToKnobs, paramsToPins, parseRoute, pinParams, reservedParams, sameKnob, storyHref, withoutPins };
|
|
173
|
-
//# sourceMappingURL=chunk-
|
|
174
|
-
//# sourceMappingURL=chunk-
|
|
173
|
+
//# sourceMappingURL=chunk-MUBZSDOI.js.map
|
|
174
|
+
//# sourceMappingURL=chunk-MUBZSDOI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/route/url.ts"],"names":[],"mappings":"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","file":"chunk-MUBZSDOI.js","sourcesContent":["import { type ConfigSchema, type ConfigShape, isConfigBranch, valueAtPath } from '@weasel-js/labkit/config';\nimport { isPlainObject } from '@weasel-js/core';\nimport { type Globals, stableStringify } from '../protocol/messages';\nimport { GLOBALS_KEY } from '../shell/globals';\n\n/**\n * Forge's URL, as pure functions: `#/<story id>?<params>`. The story and its params share the hash, so the page's\n * own query string stays the host's. A param is a knob — a story arg, addressed by its dotted config path\n * (`look.px`) — unless its name is reserved for the workshop itself.\n */\n\n/** The param a paused playhead is held in, in seconds. */\nexport const PLAYHEAD_PARAM = 't';\n\n/** Param names that are never knobs. */\nexport const RESERVED_PARAMS: ReadonlySet<string> = new Set([PLAYHEAD_PARAM]);\n\n/** Config keys forge keeps for itself, such as the `$globals` pins, start with this and never reach the URL. */\nconst INTERNAL_PREFIX = '$';\n\n/** What a forge hash holds: the story it names, and every param after it, knobs and reserved alike, in order. */\nexport interface ForgeRoute {\n story: string | null;\n params: Readonly<Record<string, string>>;\n}\n\n/** Reads a hash (`location.hash`, with or without its `#`). Anything not in the `#/<id>` form names no story. */\nexport function parseRoute(hash: string): ForgeRoute {\n const body = hash.startsWith('#') ? hash.slice(1) : hash;\n if (!body.startsWith('/')) return { story: null, params: {} };\n const at = body.indexOf('?');\n const path = at === -1 ? body.slice(1) : body.slice(1, at);\n let story: string | null;\n try {\n story = decodeURIComponent(path) || null;\n } catch {\n story = null;\n }\n const params: Record<string, string> = {};\n if (at !== -1) for (const [key, value] of new URLSearchParams(body.slice(at + 1))) params[key] = value;\n return { story, params };\n}\n\n/** The hash for `route`, with its leading `#`. The inverse of `parseRoute`. */\nexport function formatRoute(route: ForgeRoute): string {\n const query = new URLSearchParams(Object.entries(route.params)).toString();\n return `#/${encodeURIComponent(route.story ?? '')}${query ? `?${query}` : ''}`;\n}\n\n/** Whether a param name can be a knob: not reserved and not one of forge's own config keys. */\nexport function isKnobParam(name: string): boolean {\n return name !== '' && !RESERVED_PARAMS.has(name) && !name.startsWith(INTERNAL_PREFIX);\n}\n\n/** The params that are knobs, with the reserved ones left out. */\nexport function knobParams(params: Readonly<Record<string, string>>): Record<string, string> {\n return Object.fromEntries(Object.entries(params).filter(([name]) => isKnobParam(name)));\n}\n\n/** The params that are not knobs. Kept as they are when the knobs are rewritten. */\nexport function reservedParams(params: Readonly<Record<string, string>>): Record<string, string> {\n return Object.fromEntries(Object.entries(params).filter(([name]) => !isKnobParam(name)));\n}\n\n/** What a knob's value is decoded against: its schema leaf's declared kind, its default, and its choices. */\nexport interface KnobLeaf {\n kind: string | null;\n default: unknown;\n annotations?: { options?: readonly { value: string }[] };\n}\n\ntype Codec = 'number' | 'boolean' | 'string' | 'enum' | 'json';\n\n/** How a leaf's value travels: by its declared kind first, then by the type of its default. */\nfunction codecOf(leaf: KnobLeaf): Codec | null {\n switch (leaf.kind) {\n case 'number':\n case 'boolean':\n case 'string':\n case 'enum':\n return leaf.kind;\n case 'color':\n return 'string';\n case 'list':\n case 'json':\n return 'json';\n }\n const d = leaf.default;\n if (typeof d === 'number' || typeof d === 'boolean' || typeof d === 'string') return typeof d as Codec;\n return Array.isArray(d) || isPlainObject(d) ? 'json' : null;\n}\n\n/** A value as one param. Undefined for a value no param can carry, such as a function. */\nexport function encodeKnob(value: unknown): string | undefined {\n switch (typeof value) {\n case 'string':\n return value;\n case 'number':\n case 'boolean':\n return String(value);\n case 'object':\n return value !== null && (Array.isArray(value) || isPlainObject(value)) ? JSON.stringify(value) : undefined;\n default:\n return undefined;\n }\n}\n\n/** Whether `value` is something a leaf of codec `codec` could hold, so a well-formed param of the wrong type is refused. */\nfunction fits(codec: Codec, value: unknown, leaf: KnobLeaf): boolean {\n if (codec !== 'json') return true;\n const d = leaf.default;\n if (Array.isArray(d)) {\n if (!Array.isArray(value)) return false;\n return leaf.kind !== 'list' || value.every((item) => typeof item === 'string');\n }\n if (isPlainObject(d)) return isPlainObject(value);\n return true;\n}\n\n/**\n * One param read as `leaf`'s type: `{ value }`, or undefined for a param that does not parse as one — a number that\n * is not a number, an option the enum does not list, malformed JSON. A bare boolean param (`?dark`) reads as true.\n */\nexport function decodeKnob(raw: string, leaf: KnobLeaf): { value: unknown } | undefined {\n const codec = codecOf(leaf);\n switch (codec) {\n case 'number': {\n const n = raw.trim() === '' ? Number.NaN : Number(raw);\n return Number.isNaN(n) ? undefined : { value: n };\n }\n case 'boolean':\n if (raw === '' || raw === 'true' || raw === '1') return { value: true };\n if (raw === 'false' || raw === '0') return { value: false };\n return undefined;\n case 'string':\n return { value: raw };\n case 'enum': {\n const options = leaf.annotations?.options;\n return !options || options.some((o) => o.value === raw) ? { value: raw } : undefined;\n }\n case 'json': {\n try {\n const value: unknown = JSON.parse(raw);\n return fits(codec, value, leaf) ? { value } : undefined;\n } catch {\n return undefined;\n }\n }\n default:\n return undefined;\n }\n}\n\n/** One leaf a URL can address: its dotted path, and what its value decodes against. */\nexport interface KnobPath {\n path: string;\n leaf: KnobLeaf;\n}\n\n/** Every leaf of `schema` a param can carry, in schema order, reserved names left out, with branches flattened into dotted paths. */\nexport function knobPaths(schema: Pick<ConfigSchema<unknown>, 'nodes'>): KnobPath[] {\n const out: KnobPath[] = [];\n const walk = (shape: ConfigShape, at: string): void => {\n for (const [key, entry] of Object.entries(shape)) {\n if (key.startsWith(INTERNAL_PREFIX) || key.includes('.')) continue;\n const path = at === '' ? key : `${at}.${key}`;\n if (isConfigBranch(entry)) walk(entry.children, path);\n else if (codecOf(entry) !== null && isKnobParam(path)) out.push({ path, leaf: entry });\n }\n };\n walk(schema.nodes, '');\n return out;\n}\n\n/** Whether two knob values are the same value, compared as data. */\nexport function sameKnob(a: unknown, b: unknown): boolean {\n return Object.is(a, b) || stableStringify(a) === stableStringify(b);\n}\n\n/**\n * The knob params for `config`: one per leaf whose value differs from its default, keyed by dotted path, in schema\n * order. A leaf absent from `config` is at its default.\n */\nexport function knobsToParams(schema: Pick<ConfigSchema<unknown>, 'nodes'>, config: unknown): Record<string, string> {\n const params: Record<string, string> = {};\n for (const { path, leaf } of knobPaths(schema)) {\n const value = valueAtPath(config, path);\n if (value === undefined || sameKnob(value, leaf.default)) continue;\n const encoded = encodeKnob(value);\n if (encoded !== undefined) params[path] = encoded;\n }\n return params;\n}\n\n/**\n * The knob values `params` sets, by dotted path, each coerced to its leaf's type. A param naming no leaf, a reserved\n * param, and one that does not parse as its leaf's type are left out rather than failing the rest.\n */\nexport function paramsToKnobs(\n schema: Pick<ConfigSchema<unknown>, 'nodes'>,\n params: Readonly<Record<string, string>>,\n): Record<string, unknown> {\n const knobs: Record<string, unknown> = {};\n for (const { path, leaf } of knobPaths(schema)) {\n const raw = params[path];\n if (raw === undefined) continue;\n const decoded = decodeKnob(raw, leaf);\n if (decoded) knobs[path] = decoded.value;\n }\n return knobs;\n}\n\n/**\n * A link to a story at a given state, for a host that has no schema to hand: each knob is a dotted path and a value,\n * encoded by its own type. `params` adds workshop params, such as `t`.\n */\nexport function storyHref(\n story: string,\n knobs: Readonly<Record<string, unknown>> = {},\n params: Readonly<Record<string, string>> = {},\n): string {\n const encoded: Record<string, string> = {};\n for (const [path, value] of Object.entries(knobs)) {\n const raw = encodeKnob(value);\n if (raw !== undefined && isKnobParam(path)) encoded[path] = raw;\n }\n return formatRoute({ story, params: { ...encoded, ...reservedParams(params) } });\n}\n\n/** A param pinning one of the trial's globals is named by the pin's config path, `$globals.<key>`. */\nconst PIN_PREFIX = `${GLOBALS_KEY}.`;\n\n/** The params pinning a trial's globals to `globals`. Not knobs: they are read once, as the story opens, and dropped. */\nexport function pinParams(globals: Globals): Record<string, string> {\n const params: Record<string, string> = {};\n for (const [key, value] of Object.entries(globals)) if (typeof value === 'string') params[`${PIN_PREFIX}${key}`] = value;\n return params;\n}\n\n/** `params` without the ones pinning globals. */\nexport function withoutPins(params: Readonly<Record<string, string>>): Record<string, string> {\n return Object.fromEntries(Object.entries(params).filter(([name]) => !name.startsWith(PIN_PREFIX)));\n}\n\n/** The pins `params` sets, by config path: each a value its global's leaf in `schema` offers; any other is left out. */\nexport function paramsToPins(\n schema: Pick<ConfigSchema<unknown>, 'nodes'>,\n params: Readonly<Record<string, string>>,\n): Record<string, string> {\n const group = (schema.nodes as ConfigShape)[GLOBALS_KEY];\n if (!group || !isConfigBranch(group)) return {};\n const pins: Record<string, string> = {};\n for (const [key, leaf] of Object.entries(group.children)) {\n const raw = params[`${PIN_PREFIX}${key}`];\n if (raw === undefined || isConfigBranch(leaf)) continue;\n const decoded = decodeKnob(raw, leaf);\n if (typeof decoded?.value === 'string') pins[`${PIN_PREFIX}${key}`] = decoded.value;\n }\n return pins;\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -167,7 +167,7 @@ interface KnobPath {
|
|
|
167
167
|
path: string;
|
|
168
168
|
leaf: KnobLeaf;
|
|
169
169
|
}
|
|
170
|
-
/** Every leaf of `schema` a param can carry, in schema order, with branches flattened into dotted paths. */
|
|
170
|
+
/** Every leaf of `schema` a param can carry, in schema order, reserved names left out, with branches flattened into dotted paths. */
|
|
171
171
|
declare function knobPaths(schema: Pick<ConfigSchema<unknown>, 'nodes'>): KnobPath[];
|
|
172
172
|
/**
|
|
173
173
|
* The knob params for `config`: one per leaf whose value differs from its default, keyed by dotted path, in schema
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { RESERVED_PARAMS, decodeKnob, encodeKnob, formatRoute, knobParams, knobPaths, knobsToParams, paramsToKnobs, parseRoute, reservedParams, storyHref } from './chunk-
|
|
1
|
+
export { RESERVED_PARAMS, decodeKnob, encodeKnob, formatRoute, knobParams, knobPaths, knobsToParams, paramsToKnobs, parseRoute, reservedParams, storyHref } from './chunk-MUBZSDOI.js';
|
|
2
2
|
export { GALLERY_TAG, LAB_TAG } from './chunk-VUPN73JP.js';
|
|
3
3
|
export { FOLLOW_APP } from './chunk-FPF2JSWB.js';
|
|
4
4
|
export { meta, story, usePlayhead, useTimeline } from './chunk-TT4ZOYB6.js';
|
package/dist/shell/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseRoute, formatRoute, paramsToKnobs, knobPaths, sameKnob, paramsToPins, knobsToParams, PLAYHEAD_PARAM, pinParams, withoutPins, reservedParams } from '../chunk-
|
|
1
|
+
import { parseRoute, formatRoute, paramsToKnobs, knobPaths, sameKnob, paramsToPins, knobsToParams, PLAYHEAD_PARAM, pinParams, withoutPins, reservedParams } from '../chunk-MUBZSDOI.js';
|
|
2
2
|
import { DEFAULT_TITLE, ISSUES_PATH, CAPTURE_PATH, issueLabel, messageOf, MIN_DPR, MAX_DPR } from '../chunk-7YVJS4QS.js';
|
|
3
3
|
import { TITLE_LIBRARIES, loadIndexBundle, librariesFrom, LibrariesContext, LAB_DENSITY, createKitRoot, schemaFromDescription, LibraryBadge, Description, IndexPage, indexEnvOf, LabBadge, openChannel } from '../chunk-5B4RDEF3.js';
|
|
4
4
|
import { isIndexId, indexId, indexEntries } from '../chunk-ZGELUE2H.js';
|
package/dist/vite/index.js
CHANGED
|
@@ -122,19 +122,18 @@ var fileOfKey = (key) => key.slice(0, key.lastIndexOf("#"));
|
|
|
122
122
|
var SCRIPT = /\.[cm]?[jt]sx?$/;
|
|
123
123
|
var DEFAULT_LOCAL = "*default*";
|
|
124
124
|
var TYPE_KEYS = /* @__PURE__ */ new Set(["typeAnnotation", "typeParameters", "typeArguments", "returnType", "superTypeParameters", "implements"]);
|
|
125
|
+
function readModule(read, file) {
|
|
126
|
+
try {
|
|
127
|
+
return moduleInfo(read(file), file);
|
|
128
|
+
} catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
125
132
|
function createDepGraph({ root, read }) {
|
|
126
133
|
const modules = /* @__PURE__ */ new Map();
|
|
127
134
|
const resolutions = /* @__PURE__ */ new Map();
|
|
128
135
|
const info = (file) => {
|
|
129
|
-
if (!modules.has(file))
|
|
130
|
-
let parsed = null;
|
|
131
|
-
try {
|
|
132
|
-
parsed = moduleInfo(read(file), file);
|
|
133
|
-
} catch {
|
|
134
|
-
parsed = null;
|
|
135
|
-
}
|
|
136
|
-
modules.set(file, parsed);
|
|
137
|
-
}
|
|
136
|
+
if (!modules.has(file)) modules.set(file, readModule(read, file));
|
|
138
137
|
return modules.get(file) ?? null;
|
|
139
138
|
};
|
|
140
139
|
return {
|
|
@@ -146,6 +145,7 @@ function createDepGraph({ root, read }) {
|
|
|
146
145
|
},
|
|
147
146
|
reset() {
|
|
148
147
|
resolutions.clear();
|
|
148
|
+
for (const [file, parsed] of modules) if (parsed === null) modules.delete(file);
|
|
149
149
|
},
|
|
150
150
|
async build(entries, resolve6) {
|
|
151
151
|
const resolveFrom = (spec, importer) => {
|
|
@@ -737,6 +737,7 @@ function indexProgram(program, file, autoTitle2, extra, foreign) {
|
|
|
737
737
|
}
|
|
738
738
|
}
|
|
739
739
|
if (!metaNode && !program.body.some(isDefaultExport)) return [];
|
|
740
|
+
const assigned2 = assignedProps(program);
|
|
740
741
|
const meta = objectOf(metaNode, bindings, wrappers);
|
|
741
742
|
const title = stringOf(prop(meta, "title"), bindings) ?? autoTitle2;
|
|
742
743
|
const include = storyFilter(meta, "includeStories");
|
|
@@ -747,7 +748,7 @@ function indexProgram(program, file, autoTitle2, extra, foreign) {
|
|
|
747
748
|
const metaTags = tagsOf(meta);
|
|
748
749
|
const native = wrappers.has(calleeOf(metaNode, bindings) ?? "");
|
|
749
750
|
return exported.filter(({ name }) => name !== "__namedExportsOrder").filter(({ name }) => (!include || include(name)) && (!exclude || !exclude(name))).filter((e) => !native || (e.from ? foreign?.reexport(e.name) ?? true : mayBeStory(e.node, { bindings, wrappers, foreign }))).map(({ name, node, doc }) => {
|
|
750
|
-
const spec = objectOf(node, bindings, wrappers);
|
|
751
|
+
const spec = withAssigned(objectOf(node, bindings, wrappers), assigned2.get(name));
|
|
751
752
|
const isolate = isolateOf(spec, bindings, wrappers, name) ?? metaIsolate;
|
|
752
753
|
const tags = combineTags(metaTags, tagsOf(spec));
|
|
753
754
|
const viewport = native ? viewportOf(spec, bindings, wrappers) : void 0;
|
|
@@ -766,6 +767,23 @@ function indexProgram(program, file, autoTitle2, extra, foreign) {
|
|
|
766
767
|
};
|
|
767
768
|
});
|
|
768
769
|
}
|
|
770
|
+
function assignedProps(program) {
|
|
771
|
+
const out = /* @__PURE__ */ new Map();
|
|
772
|
+
for (const stmt of program.body) {
|
|
773
|
+
const e = stmt.type === "ExpressionStatement" ? stmt.expression : void 0;
|
|
774
|
+
if (e?.type !== "AssignmentExpression" || e.operator !== "=" || e.left.type !== "MemberExpression") continue;
|
|
775
|
+
const { object, property, computed } = e.left;
|
|
776
|
+
if (object.type !== "Identifier" || computed || property.type !== "Identifier") continue;
|
|
777
|
+
const props = out.get(object.name) ?? [];
|
|
778
|
+
props.push({ type: "ObjectProperty", key: property, value: e.right, computed: false, shorthand: false });
|
|
779
|
+
out.set(object.name, props);
|
|
780
|
+
}
|
|
781
|
+
return out;
|
|
782
|
+
}
|
|
783
|
+
function withAssigned(spec, props) {
|
|
784
|
+
if (!props) return spec;
|
|
785
|
+
return { type: "ObjectExpression", properties: [...[...props].reverse(), ...spec?.properties ?? []] };
|
|
786
|
+
}
|
|
769
787
|
function isolateOf(obj, bindings, wrappers, exportName) {
|
|
770
788
|
const parameters = objectOf(prop(obj, "parameters"), bindings, wrappers);
|
|
771
789
|
const forge2 = objectOf(prop(parameters, "forge"), bindings, wrappers);
|
|
@@ -2190,6 +2208,23 @@ function watchSources(server, { files, depGraph, reindex, redeps, logError }) {
|
|
|
2190
2208
|
});
|
|
2191
2209
|
}
|
|
2192
2210
|
}
|
|
2211
|
+
function coalesced(run, onError) {
|
|
2212
|
+
let running = false;
|
|
2213
|
+
let next = null;
|
|
2214
|
+
const start = (arg) => {
|
|
2215
|
+
running = true;
|
|
2216
|
+
run(arg).catch(onError).finally(() => {
|
|
2217
|
+
running = false;
|
|
2218
|
+
const queued = next;
|
|
2219
|
+
next = null;
|
|
2220
|
+
if (queued) start(queued.arg);
|
|
2221
|
+
});
|
|
2222
|
+
};
|
|
2223
|
+
return (arg) => {
|
|
2224
|
+
if (running) next = { arg };
|
|
2225
|
+
else start(arg);
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
2193
2228
|
function companions(options, files) {
|
|
2194
2229
|
const { storybookShims: shims, propControls: controls, api } = options;
|
|
2195
2230
|
const storyFiles = () => [...files().keys()];
|
|
@@ -2212,7 +2247,6 @@ function forge(options) {
|
|
|
2212
2247
|
let logger;
|
|
2213
2248
|
let deps = null;
|
|
2214
2249
|
let depsSent = null;
|
|
2215
|
-
let depsPending = null;
|
|
2216
2250
|
const wrappersOf = /* @__PURE__ */ new Map();
|
|
2217
2251
|
let settledAll = null;
|
|
2218
2252
|
const glob = () => {
|
|
@@ -2285,20 +2319,17 @@ function forge(options) {
|
|
|
2285
2319
|
}
|
|
2286
2320
|
}
|
|
2287
2321
|
};
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
const
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
depsPending = null;
|
|
2300
|
-
});
|
|
2301
|
-
}
|
|
2322
|
+
const rebuild = coalesced(async (server) => {
|
|
2323
|
+
const graph = await graphOf(async (spec, importer) => (await server.environments.client.pluginContainer.resolveId(spec, importer))?.id ?? null);
|
|
2324
|
+
const json3 = JSON.stringify(graph);
|
|
2325
|
+
if (json3 === depsSent) return;
|
|
2326
|
+
depsSent = json3;
|
|
2327
|
+
invalidate(server, ["deps.js"]);
|
|
2328
|
+
server.ws.send({ type: "custom", event: "forge:deps", data: graph });
|
|
2329
|
+
}, logError);
|
|
2330
|
+
const redeps = (server) => {
|
|
2331
|
+
if (depsSent !== null) rebuild(server);
|
|
2332
|
+
};
|
|
2302
2333
|
const storiesReaching = (changed) => {
|
|
2303
2334
|
const current = files();
|
|
2304
2335
|
const seen = /* @__PURE__ */ new Set();
|