@hyperspan/framework 2.0.0 → 2.0.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/actions.js +109 -0
- package/dist/callsites.js +18 -0
- package/dist/client/css.js +6 -0
- package/dist/client/js.js +314 -0
- package/dist/client/manifest.js +55 -0
- package/dist/cookies.js +142 -0
- package/dist/dev-bindings.js +15 -0
- package/dist/fetch-handler.js +108 -0
- package/dist/html.js +1 -0
- package/dist/index.js +50 -0
- package/dist/island.js +17 -0
- package/dist/layout.js +42 -0
- package/dist/middleware.js +89 -0
- package/dist/register-routes.js +41 -0
- package/dist/server.js +580 -0
- package/dist/ssr/install-server-dom-mock.js +2 -0
- package/dist/ssr/mock-dom.js +370 -0
- package/dist/utils.js +157 -0
- package/package.json +25 -18
- package/.claude/settings.local.json +0 -9
- package/tsconfig.json +0 -25
package/dist/actions.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { html } from "./html.js";
|
|
2
|
+
import { createRoute, returnHTMLResponse } from "./server.js";
|
|
3
|
+
import { assetHash, formDataToJSON } from "./utils.js";
|
|
4
|
+
import { hyperspanActionsScriptTag } from "./layout.js";
|
|
5
|
+
import { validateBody } from "./middleware.js";
|
|
6
|
+
import debug from "debug";
|
|
7
|
+
const log = debug("hyperspan:actions");
|
|
8
|
+
function createAction(params) {
|
|
9
|
+
const { name, schema } = params;
|
|
10
|
+
const path = `/__actions/${assetHash(name)}`;
|
|
11
|
+
let _handler = null;
|
|
12
|
+
let _errorHandler = null;
|
|
13
|
+
function actionResponseOptions(status) {
|
|
14
|
+
return {
|
|
15
|
+
...route._serverConfig?.responseOptions ?? {},
|
|
16
|
+
...route._config?.responseOptions ?? {},
|
|
17
|
+
...status !== void 0 ? { status } : {}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const route = createRoute({ path, name }).get((c) => api.render(c)).post(
|
|
21
|
+
async (c) => {
|
|
22
|
+
if (!_handler) {
|
|
23
|
+
throw new Error("Action POST handler not set! Every action must have a POST handler.");
|
|
24
|
+
}
|
|
25
|
+
const data = c.vars.body || formDataToJSON(await c.req.formData()) || {};
|
|
26
|
+
log("POST handler", { data });
|
|
27
|
+
const response = await _handler(c, { data });
|
|
28
|
+
log("POST handler response", { response });
|
|
29
|
+
if (response instanceof Response) {
|
|
30
|
+
if ([301, 302, 307, 308].includes(response.status)) {
|
|
31
|
+
response.headers.set("X-Redirect-Location", response.headers.get("Location") || "/");
|
|
32
|
+
response.headers.delete("Location");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return response;
|
|
36
|
+
},
|
|
37
|
+
{ middleware: schema ? [validateBody(schema)] : [] }
|
|
38
|
+
).errorHandler(async (c, err) => {
|
|
39
|
+
const data = c.vars.body || formDataToJSON(await c.req.formData()) || {};
|
|
40
|
+
const error = err._error || err;
|
|
41
|
+
c.res.status = err._error ? 400 : 500;
|
|
42
|
+
log("errorHandler", { data, error });
|
|
43
|
+
return await returnHTMLResponse(
|
|
44
|
+
c,
|
|
45
|
+
() => {
|
|
46
|
+
return _errorHandler ? _errorHandler(c, { data, error }) : api.render(c, { data, error });
|
|
47
|
+
},
|
|
48
|
+
actionResponseOptions(c.res.status ?? 400)
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
route._config.name = name;
|
|
52
|
+
const api = {
|
|
53
|
+
_kind: "hsAction",
|
|
54
|
+
_config: route._config,
|
|
55
|
+
get _serverConfig() {
|
|
56
|
+
return route._serverConfig;
|
|
57
|
+
},
|
|
58
|
+
set _serverConfig(config) {
|
|
59
|
+
route._serverConfig = config;
|
|
60
|
+
},
|
|
61
|
+
_path() {
|
|
62
|
+
return path;
|
|
63
|
+
},
|
|
64
|
+
_form: null,
|
|
65
|
+
/**
|
|
66
|
+
* Form to render
|
|
67
|
+
* This will be wrapped in a <hs-action> web component and submitted via fetch()
|
|
68
|
+
*/
|
|
69
|
+
form(_formFn) {
|
|
70
|
+
api._form = _formFn;
|
|
71
|
+
return api;
|
|
72
|
+
},
|
|
73
|
+
/**
|
|
74
|
+
* Process form data
|
|
75
|
+
*
|
|
76
|
+
* Returns result from form processing if successful
|
|
77
|
+
* Re-renders form with data and error information otherwise
|
|
78
|
+
*/
|
|
79
|
+
post(handler) {
|
|
80
|
+
_handler = handler;
|
|
81
|
+
return api;
|
|
82
|
+
},
|
|
83
|
+
/**
|
|
84
|
+
* Get form renderer method
|
|
85
|
+
*/
|
|
86
|
+
render(c, props) {
|
|
87
|
+
const formContent = api._form ? api._form(c, props || {}) : null;
|
|
88
|
+
return formContent ? html`<hs-action url="${this._path()}">${formContent}</hs-action
|
|
89
|
+
>${hyperspanActionsScriptTag()}` : null;
|
|
90
|
+
},
|
|
91
|
+
errorHandler(handler) {
|
|
92
|
+
_errorHandler = handler;
|
|
93
|
+
return api;
|
|
94
|
+
},
|
|
95
|
+
use(middleware, opts) {
|
|
96
|
+
route.use(middleware, opts);
|
|
97
|
+
return api;
|
|
98
|
+
},
|
|
99
|
+
middleware(middleware, opts) {
|
|
100
|
+
route.middleware(middleware, opts);
|
|
101
|
+
return api;
|
|
102
|
+
},
|
|
103
|
+
fetch: route.fetch
|
|
104
|
+
};
|
|
105
|
+
return api;
|
|
106
|
+
}
|
|
107
|
+
export {
|
|
108
|
+
createAction
|
|
109
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function callsites() {
|
|
2
|
+
const _prepareStackTrace = Error.prepareStackTrace;
|
|
3
|
+
try {
|
|
4
|
+
let result = [];
|
|
5
|
+
Error.prepareStackTrace = (_, callSites) => {
|
|
6
|
+
const callSitesWithoutCurrent = callSites.slice(1);
|
|
7
|
+
result = callSitesWithoutCurrent;
|
|
8
|
+
return callSitesWithoutCurrent;
|
|
9
|
+
};
|
|
10
|
+
new Error().stack;
|
|
11
|
+
return result;
|
|
12
|
+
} finally {
|
|
13
|
+
Error.prepareStackTrace = _prepareStackTrace;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
callsites
|
|
18
|
+
};
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
var __freeze = Object.freeze;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __template = (cooked, raw) => __freeze(__defProp(cooked, "raw", { value: __freeze(raw || cooked.slice()) }));
|
|
4
|
+
var _a, _b, _c, _d;
|
|
5
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
6
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { html } from "../html.js";
|
|
9
|
+
import { assetHash as assetHashFn } from "../utils.js";
|
|
10
|
+
import { getImportMap, registerImport, resolveImport } from "./manifest.js";
|
|
11
|
+
import { registerImport as registerImport2, resolveImport as resolveImport2, getImportMap as getImportMap2 } from "./manifest.js";
|
|
12
|
+
const JS_PUBLIC_PATH = "/_hs/js";
|
|
13
|
+
const JS_ISLAND_PUBLIC_PATH = "/_hs/js/islands";
|
|
14
|
+
const CLIENT_JS_REGISTRY = /* @__PURE__ */ Symbol.for("@hyperspan/client-js-entries");
|
|
15
|
+
const CLIENT_JS_PATH_IDENTITIES = /* @__PURE__ */ Symbol.for("@hyperspan/client-js-path-identities");
|
|
16
|
+
const PATH_ALIASES = /* @__PURE__ */ Symbol.for("@hyperspan/path-aliases");
|
|
17
|
+
function getPathAliases() {
|
|
18
|
+
const globalAliases = globalThis;
|
|
19
|
+
if (!globalAliases[PATH_ALIASES]) {
|
|
20
|
+
globalAliases[PATH_ALIASES] = {};
|
|
21
|
+
}
|
|
22
|
+
return globalAliases[PATH_ALIASES];
|
|
23
|
+
}
|
|
24
|
+
function registerPathAliases(aliases) {
|
|
25
|
+
Object.assign(getPathAliases(), aliases);
|
|
26
|
+
}
|
|
27
|
+
function resolveWithAliases(specifier) {
|
|
28
|
+
const aliases = getPathAliases();
|
|
29
|
+
const keys = Object.keys(aliases).sort((a, b) => b.length - a.length);
|
|
30
|
+
for (const key of keys) {
|
|
31
|
+
if (specifier === key || specifier.startsWith(key)) {
|
|
32
|
+
const rest = specifier.slice(key.length).replace(/^\//, "");
|
|
33
|
+
return join(aliases[key], rest);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
function getPathIdentityClientJS() {
|
|
39
|
+
const globalPathIdentities = globalThis;
|
|
40
|
+
if (!globalPathIdentities[CLIENT_JS_PATH_IDENTITIES]) {
|
|
41
|
+
globalPathIdentities[CLIENT_JS_PATH_IDENTITIES] = [];
|
|
42
|
+
}
|
|
43
|
+
return globalPathIdentities[CLIENT_JS_PATH_IDENTITIES];
|
|
44
|
+
}
|
|
45
|
+
function getClientJSRegistry() {
|
|
46
|
+
const globalRegistry = globalThis;
|
|
47
|
+
if (!globalRegistry[CLIENT_JS_REGISTRY]) {
|
|
48
|
+
globalRegistry[CLIENT_JS_REGISTRY] = /* @__PURE__ */ new Map();
|
|
49
|
+
}
|
|
50
|
+
return globalRegistry[CLIENT_JS_REGISTRY];
|
|
51
|
+
}
|
|
52
|
+
const JS_IMPORT_MAP = {
|
|
53
|
+
get size() {
|
|
54
|
+
return Object.keys(getImportMap()).length;
|
|
55
|
+
},
|
|
56
|
+
keys() {
|
|
57
|
+
return Object.keys(getImportMap()).values();
|
|
58
|
+
},
|
|
59
|
+
has(key) {
|
|
60
|
+
return resolveImport(key) !== void 0;
|
|
61
|
+
},
|
|
62
|
+
get(key) {
|
|
63
|
+
return resolveImport(key);
|
|
64
|
+
},
|
|
65
|
+
set(key, value) {
|
|
66
|
+
registerImport(key, value);
|
|
67
|
+
return this;
|
|
68
|
+
},
|
|
69
|
+
entries() {
|
|
70
|
+
return Object.entries(getImportMap()).values();
|
|
71
|
+
},
|
|
72
|
+
[Symbol.iterator]() {
|
|
73
|
+
return Object.entries(getImportMap())[Symbol.iterator]();
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
function stableClientSourceKey(absPath) {
|
|
77
|
+
const normalized = absPath.replace(/\\/g, "/");
|
|
78
|
+
const marker = "/node_modules/";
|
|
79
|
+
const idx = normalized.lastIndexOf(marker);
|
|
80
|
+
if (idx !== -1) {
|
|
81
|
+
return normalized.slice(idx + marker.length);
|
|
82
|
+
}
|
|
83
|
+
if (typeof process !== "undefined" && typeof process.cwd === "function") {
|
|
84
|
+
const rel = relative(process.cwd(), absPath).replace(/\\/g, "/");
|
|
85
|
+
if (rel && !rel.startsWith("..") && !isAbsolute(rel)) {
|
|
86
|
+
return rel;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return normalized;
|
|
90
|
+
}
|
|
91
|
+
function toFilePath(modulePath) {
|
|
92
|
+
return modulePath.startsWith("file://") ? fileURLToPath(modulePath) : modulePath;
|
|
93
|
+
}
|
|
94
|
+
function tryResolveToFile(specifier) {
|
|
95
|
+
try {
|
|
96
|
+
if (typeof import.meta.resolve !== "function") {
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
const resolved = import.meta.resolve(specifier);
|
|
100
|
+
if (typeof resolved === "string" && (resolved.startsWith("file://") || isAbsolute(resolved))) {
|
|
101
|
+
return toFilePath(resolved);
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
}
|
|
105
|
+
return void 0;
|
|
106
|
+
}
|
|
107
|
+
function clientPublicPath(esmName) {
|
|
108
|
+
return resolveImport(esmName) ?? `${JS_PUBLIC_PATH}/${esmName}.js`;
|
|
109
|
+
}
|
|
110
|
+
function clientIdentityKey(specifier) {
|
|
111
|
+
if (specifier.startsWith("file://") || isAbsolute(specifier)) {
|
|
112
|
+
return stableClientSourceKey(toFilePath(specifier));
|
|
113
|
+
}
|
|
114
|
+
return specifier;
|
|
115
|
+
}
|
|
116
|
+
function resolveClientAbsPath(specifier) {
|
|
117
|
+
if (specifier.startsWith("file://") || isAbsolute(specifier)) {
|
|
118
|
+
return toFilePath(specifier);
|
|
119
|
+
}
|
|
120
|
+
const aliased = resolveWithAliases(specifier);
|
|
121
|
+
if (aliased) {
|
|
122
|
+
return aliased;
|
|
123
|
+
}
|
|
124
|
+
const cwd = typeof process !== "undefined" && typeof process.cwd === "function" ? process.cwd() : "";
|
|
125
|
+
return tryResolveToFile(specifier) ?? (cwd ? join(cwd, specifier) : specifier);
|
|
126
|
+
}
|
|
127
|
+
function readClientSource(absPath) {
|
|
128
|
+
try {
|
|
129
|
+
if (existsSync(absPath)) {
|
|
130
|
+
return readFileSync(absPath, "utf-8");
|
|
131
|
+
}
|
|
132
|
+
} catch {
|
|
133
|
+
}
|
|
134
|
+
return void 0;
|
|
135
|
+
}
|
|
136
|
+
function getClientJSEntries() {
|
|
137
|
+
return [...getClientJSRegistry().values()];
|
|
138
|
+
}
|
|
139
|
+
function getClientJSEntryByEsmName(esmName) {
|
|
140
|
+
return getClientJSRegistry().get(esmName);
|
|
141
|
+
}
|
|
142
|
+
function resetClientJSEntriesForTests() {
|
|
143
|
+
getClientJSRegistry().clear();
|
|
144
|
+
getPathIdentityClientJS().length = 0;
|
|
145
|
+
const aliases = getPathAliases();
|
|
146
|
+
for (const key of Object.keys(aliases)) {
|
|
147
|
+
delete aliases[key];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function registerClientJS(modulePathResolved, options = {}) {
|
|
151
|
+
const type = options.type ?? "module";
|
|
152
|
+
const specifier = modulePathResolved.replace(/\\/g, "/");
|
|
153
|
+
if (specifier.startsWith(".")) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`[Hyperspan] buildClientJS(${JSON.stringify(modulePathResolved)}) got a relative path, which has no stable identity across dev, build, and deploy. Use a tsconfig alias like '~/app/client/file.ts' \u2014 the build resolves it, and every runtime (including Workers, which cannot resolve paths) matches it in the asset manifest.`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
const identityKey = clientIdentityKey(specifier);
|
|
159
|
+
const identityFromPath = identityKey !== specifier;
|
|
160
|
+
const hash = assetHashFn(identityKey);
|
|
161
|
+
const esmName = `client-${hash}`;
|
|
162
|
+
if (identityFromPath) {
|
|
163
|
+
getPathIdentityClientJS().push({ modulePath: modulePathResolved, identityKey });
|
|
164
|
+
}
|
|
165
|
+
let absPath;
|
|
166
|
+
let discovered;
|
|
167
|
+
function currentAbsPath() {
|
|
168
|
+
return absPath ??= resolveClientAbsPath(specifier);
|
|
169
|
+
}
|
|
170
|
+
function currentExports() {
|
|
171
|
+
if (!discovered) {
|
|
172
|
+
const source = readClientSource(currentAbsPath());
|
|
173
|
+
discovered = source ? discoverClientExports(source) : { exports: "* as _module", fnArgs: "_module" };
|
|
174
|
+
}
|
|
175
|
+
return discovered;
|
|
176
|
+
}
|
|
177
|
+
const entry = {
|
|
178
|
+
modulePath: modulePathResolved,
|
|
179
|
+
get absPath() {
|
|
180
|
+
return currentAbsPath();
|
|
181
|
+
},
|
|
182
|
+
identityKey,
|
|
183
|
+
identityFromPath,
|
|
184
|
+
assetHash: hash,
|
|
185
|
+
esmName,
|
|
186
|
+
get publicPath() {
|
|
187
|
+
return clientPublicPath(esmName);
|
|
188
|
+
},
|
|
189
|
+
get exports() {
|
|
190
|
+
return currentExports().exports;
|
|
191
|
+
},
|
|
192
|
+
get fnArgs() {
|
|
193
|
+
return currentExports().fnArgs;
|
|
194
|
+
},
|
|
195
|
+
type
|
|
196
|
+
};
|
|
197
|
+
getClientJSRegistry().set(esmName, entry);
|
|
198
|
+
registerImport(esmName, entry.publicPath);
|
|
199
|
+
return {
|
|
200
|
+
assetHash: hash,
|
|
201
|
+
esmName,
|
|
202
|
+
get publicPath() {
|
|
203
|
+
return clientPublicPath(esmName);
|
|
204
|
+
},
|
|
205
|
+
renderScriptTag: (loadScript) => {
|
|
206
|
+
if (type === "iife") {
|
|
207
|
+
return html(_a || (_a = __template(['<script src="', '"><\/script>'])), clientPublicPath(esmName));
|
|
208
|
+
}
|
|
209
|
+
const t = typeof loadScript;
|
|
210
|
+
const { exports, fnArgs } = currentExports();
|
|
211
|
+
if (t === "string") {
|
|
212
|
+
return html(_b || (_b = __template(['\n <script type="module" data-source-id="', '">\n import ', " from '", "';\n (", ")(", ");\n <\/script>\n "])), hash, exports, esmName, html.raw(loadScript), fnArgs);
|
|
213
|
+
}
|
|
214
|
+
if (t === "function") {
|
|
215
|
+
return html(_c || (_c = __template(['\n <script type="module" data-source-id="', '">\n import ', " from '", "';\n (", ")(", ");\n <\/script>\n "])), hash, exports, esmName, html.raw(functionToString(loadScript)), fnArgs);
|
|
216
|
+
}
|
|
217
|
+
return html(_d || (_d = __template(['\n <script type="module" data-source-id="', `">
|
|
218
|
+
import '`, "';\n <\/script>\n "])), hash, esmName);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
async function buildClientJS(modulePathResolved, options = {}) {
|
|
223
|
+
return registerClientJS(modulePathResolved, options);
|
|
224
|
+
}
|
|
225
|
+
const streamingClient = registerClientJS(
|
|
226
|
+
"@hyperspan/framework/client/_hs/hyperspan-streaming.client.ts",
|
|
227
|
+
{ type: "iife" }
|
|
228
|
+
);
|
|
229
|
+
const actionsClient = registerClientJS(
|
|
230
|
+
"@hyperspan/framework/client/_hs/hyperspan-actions.client.ts"
|
|
231
|
+
);
|
|
232
|
+
function discoverClientExports(contents) {
|
|
233
|
+
const bundled = extractExports(contents);
|
|
234
|
+
if (bundled.exports !== "* as _module") {
|
|
235
|
+
return bundled;
|
|
236
|
+
}
|
|
237
|
+
const names = [];
|
|
238
|
+
const seen = /* @__PURE__ */ new Set();
|
|
239
|
+
for (const re of [
|
|
240
|
+
/export\s+(?:async\s+)?function\s+([A-Za-z_$][\w$]*)/g,
|
|
241
|
+
/export\s+const\s+([A-Za-z_$][\w$]*)/g,
|
|
242
|
+
/export\s+class\s+([A-Za-z_$][\w$]*)/g,
|
|
243
|
+
/export\s+let\s+([A-Za-z_$][\w$]*)/g
|
|
244
|
+
]) {
|
|
245
|
+
let match;
|
|
246
|
+
while ((match = re.exec(contents)) !== null) {
|
|
247
|
+
if (!seen.has(match[1])) {
|
|
248
|
+
names.push(match[1]);
|
|
249
|
+
seen.add(match[1]);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const exportBlock = /export\s*\{([^}]+)\}/g;
|
|
254
|
+
let block;
|
|
255
|
+
while ((block = exportBlock.exec(contents)) !== null) {
|
|
256
|
+
for (const part of block[1].split(",")) {
|
|
257
|
+
const trimmed = part.trim();
|
|
258
|
+
if (!trimmed || trimmed.startsWith("type ")) continue;
|
|
259
|
+
const asMatch = trimmed.match(/^(?:([\w$]+)\s+as\s+)?([\w$]+)$/);
|
|
260
|
+
const name = asMatch?.[2] ?? trimmed;
|
|
261
|
+
if (name && name !== "default" && !seen.has(name)) {
|
|
262
|
+
names.push(name);
|
|
263
|
+
seen.add(name);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (names.length === 0) {
|
|
268
|
+
if (/export\s+default\b/.test(contents)) {
|
|
269
|
+
return { exports: "DefaultExport", fnArgs: "DefaultExport" };
|
|
270
|
+
}
|
|
271
|
+
return { exports: "* as _module", fnArgs: "_module" };
|
|
272
|
+
}
|
|
273
|
+
const exports = `{${names.join(", ")}}`;
|
|
274
|
+
return { exports, fnArgs: exports };
|
|
275
|
+
}
|
|
276
|
+
function extractExports(contents) {
|
|
277
|
+
const exportRegex = /export\{(.*)\}/g;
|
|
278
|
+
const exportLine = exportRegex.exec(contents);
|
|
279
|
+
let exports = "{}";
|
|
280
|
+
let fnArgs = "{}";
|
|
281
|
+
if (exportLine) {
|
|
282
|
+
const exportName = exportLine[1];
|
|
283
|
+
exports = "{" + exportName.split(",").map((name) => name.trim().split(" as ")).map(([name, alias]) => `${alias === "default" ? "default as " + name : alias}`).join(", ") + "}";
|
|
284
|
+
}
|
|
285
|
+
fnArgs = exports.replace(/(\w+)\s*as\s*(\w+)/g, "$1: $2").trim();
|
|
286
|
+
if (exports === "{}" && fnArgs === "{}") {
|
|
287
|
+
exports = "* as _module";
|
|
288
|
+
fnArgs = "_module";
|
|
289
|
+
}
|
|
290
|
+
return { exports, fnArgs };
|
|
291
|
+
}
|
|
292
|
+
function functionToString(fn) {
|
|
293
|
+
return fn.toString().trim();
|
|
294
|
+
}
|
|
295
|
+
export {
|
|
296
|
+
JS_IMPORT_MAP,
|
|
297
|
+
JS_ISLAND_PUBLIC_PATH,
|
|
298
|
+
JS_PUBLIC_PATH,
|
|
299
|
+
actionsClient,
|
|
300
|
+
buildClientJS,
|
|
301
|
+
discoverClientExports,
|
|
302
|
+
extractExports,
|
|
303
|
+
functionToString,
|
|
304
|
+
getClientJSEntries,
|
|
305
|
+
getClientJSEntryByEsmName,
|
|
306
|
+
getImportMap2 as getImportMap,
|
|
307
|
+
getPathIdentityClientJS,
|
|
308
|
+
registerImport2 as registerImport,
|
|
309
|
+
registerPathAliases,
|
|
310
|
+
resetClientJSEntriesForTests,
|
|
311
|
+
resolveImport2 as resolveImport,
|
|
312
|
+
stableClientSourceKey,
|
|
313
|
+
streamingClient
|
|
314
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const MANIFEST_KEY = /* @__PURE__ */ Symbol.for("@hyperspan/asset-manifest");
|
|
2
|
+
function sharedManifest() {
|
|
3
|
+
const globalStore = globalThis;
|
|
4
|
+
if (!globalStore[MANIFEST_KEY]) {
|
|
5
|
+
globalStore[MANIFEST_KEY] = { imports: {}, css: {}, clients: {} };
|
|
6
|
+
}
|
|
7
|
+
return globalStore[MANIFEST_KEY];
|
|
8
|
+
}
|
|
9
|
+
function setAssetManifest(manifest) {
|
|
10
|
+
const store = sharedManifest();
|
|
11
|
+
store.imports = { ...manifest.imports ?? {} };
|
|
12
|
+
store.css = { ...manifest.css ?? {} };
|
|
13
|
+
store.clients = { ...manifest.clients ?? {} };
|
|
14
|
+
}
|
|
15
|
+
function getAssetManifest() {
|
|
16
|
+
return sharedManifest();
|
|
17
|
+
}
|
|
18
|
+
function resolveImport(name) {
|
|
19
|
+
return sharedManifest().imports[name];
|
|
20
|
+
}
|
|
21
|
+
function getRouteCss(path) {
|
|
22
|
+
return sharedManifest().css[path] ?? [];
|
|
23
|
+
}
|
|
24
|
+
function getImportMap() {
|
|
25
|
+
return { ...sharedManifest().imports };
|
|
26
|
+
}
|
|
27
|
+
function registerImport(name, publicPath) {
|
|
28
|
+
sharedManifest().imports[name] = publicPath;
|
|
29
|
+
}
|
|
30
|
+
function getClientJSFromManifest(moduleId, _exportNames = "default") {
|
|
31
|
+
const publicPath = sharedManifest().clients[moduleId];
|
|
32
|
+
if (!publicPath) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`[Hyperspan] Client module "${moduleId}" not found in asset manifest. Run hyperspan build or start dev server.`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const esmName = publicPath.split("/").pop()?.replace(".js", "") ?? moduleId;
|
|
38
|
+
return {
|
|
39
|
+
assetHash: moduleId,
|
|
40
|
+
esmName,
|
|
41
|
+
publicPath,
|
|
42
|
+
renderScriptTag: () => {
|
|
43
|
+
throw new Error("renderScriptTag requires html template - use layout helpers instead");
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
getAssetManifest,
|
|
49
|
+
getClientJSFromManifest,
|
|
50
|
+
getImportMap,
|
|
51
|
+
getRouteCss,
|
|
52
|
+
registerImport,
|
|
53
|
+
resolveImport,
|
|
54
|
+
setAssetManifest
|
|
55
|
+
};
|
package/dist/cookies.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
const REGEXP_PAIR_SPLIT = /; */;
|
|
2
|
+
const REGEXP_FIELD_CONTENT = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
|
|
3
|
+
class Cookies {
|
|
4
|
+
_req;
|
|
5
|
+
_responseHeaders;
|
|
6
|
+
_parsedCookies = {};
|
|
7
|
+
_encrypt;
|
|
8
|
+
_decrypt;
|
|
9
|
+
constructor(req, responseHeaders = void 0) {
|
|
10
|
+
this._req = req;
|
|
11
|
+
this._responseHeaders = responseHeaders;
|
|
12
|
+
this._parsedCookies = parse(req.headers.get("Cookie") || "");
|
|
13
|
+
}
|
|
14
|
+
get(name) {
|
|
15
|
+
const value = this._parsedCookies[name];
|
|
16
|
+
if (value && this._decrypt) {
|
|
17
|
+
return this._decrypt(value);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
set(name, value, options) {
|
|
22
|
+
if (!this._responseHeaders) {
|
|
23
|
+
throw new Error("Set cookies in the response object. Cookies can only be read from the request object.");
|
|
24
|
+
}
|
|
25
|
+
if (this._encrypt) {
|
|
26
|
+
value = this._encrypt(value);
|
|
27
|
+
}
|
|
28
|
+
this._responseHeaders.append("Set-Cookie", serialize(name, value, options));
|
|
29
|
+
}
|
|
30
|
+
delete(name) {
|
|
31
|
+
this.set(name, "", { expires: /* @__PURE__ */ new Date(0) });
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Set the encoder and decoder functions for the cookies and re-parse the cookie header
|
|
35
|
+
*/
|
|
36
|
+
setEncryption(encrypt, decrypt) {
|
|
37
|
+
this._encrypt = encrypt;
|
|
38
|
+
this._decrypt = decrypt;
|
|
39
|
+
this._parsedCookies = parse(this._req.headers.get("Cookie") || "");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/*!
|
|
43
|
+
* cookie
|
|
44
|
+
* @source https://github.com/jkohrman/cookie-parse/blob/master/index.js
|
|
45
|
+
* Copyright(c) 2012-2014 Roman Shtylman
|
|
46
|
+
* Copyright(c) 2015 Douglas Christopher Wilson
|
|
47
|
+
* Copyright(c) 2016 Jeff Kohrman
|
|
48
|
+
* MIT Licensed
|
|
49
|
+
*/
|
|
50
|
+
function parse(str) {
|
|
51
|
+
if (typeof str !== "string") {
|
|
52
|
+
throw new TypeError("argument str must be a string");
|
|
53
|
+
}
|
|
54
|
+
const obj = {};
|
|
55
|
+
const pairs = str.split(REGEXP_PAIR_SPLIT);
|
|
56
|
+
for (let i = 0; i < pairs.length; i++) {
|
|
57
|
+
const pair = pairs[i];
|
|
58
|
+
let eq_idx = pair.indexOf("=");
|
|
59
|
+
let key;
|
|
60
|
+
let val;
|
|
61
|
+
if (eq_idx < 0) {
|
|
62
|
+
key = pair.trim();
|
|
63
|
+
val = "true";
|
|
64
|
+
} else {
|
|
65
|
+
key = pair.substring(0, eq_idx).trim();
|
|
66
|
+
val = pair.substring(eq_idx + 1, eq_idx + 1 + pair.length).trim();
|
|
67
|
+
}
|
|
68
|
+
;
|
|
69
|
+
if ('"' == val[0]) {
|
|
70
|
+
val = val.slice(1, -1);
|
|
71
|
+
}
|
|
72
|
+
if (void 0 == obj[key]) {
|
|
73
|
+
obj[key] = tryDecode(val, decodeURIComponent);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return obj;
|
|
77
|
+
}
|
|
78
|
+
function serialize(name, val, options = {}) {
|
|
79
|
+
const opt = options || {};
|
|
80
|
+
if (!REGEXP_FIELD_CONTENT.test(name)) {
|
|
81
|
+
throw new TypeError("argument name is invalid");
|
|
82
|
+
}
|
|
83
|
+
let value = encodeURIComponent(val);
|
|
84
|
+
if (value && !REGEXP_FIELD_CONTENT.test(value)) {
|
|
85
|
+
throw new TypeError("argument val is invalid");
|
|
86
|
+
}
|
|
87
|
+
let str = name + "=" + value;
|
|
88
|
+
if (null != opt.maxAge) {
|
|
89
|
+
const maxAge = opt.maxAge - 0;
|
|
90
|
+
if (isNaN(maxAge)) throw new Error("maxAge should be a Number");
|
|
91
|
+
str += "; Max-Age=" + Math.floor(maxAge);
|
|
92
|
+
}
|
|
93
|
+
if (opt.domain) {
|
|
94
|
+
if (!REGEXP_FIELD_CONTENT.test(opt.domain)) {
|
|
95
|
+
throw new TypeError("option domain is invalid");
|
|
96
|
+
}
|
|
97
|
+
str += "; Domain=" + opt.domain;
|
|
98
|
+
}
|
|
99
|
+
if (opt.path) {
|
|
100
|
+
if (!REGEXP_FIELD_CONTENT.test(opt.path)) {
|
|
101
|
+
throw new TypeError("option path is invalid");
|
|
102
|
+
}
|
|
103
|
+
str += "; Path=" + opt.path;
|
|
104
|
+
}
|
|
105
|
+
if (opt.expires) {
|
|
106
|
+
if (typeof opt.expires.toUTCString !== "function") {
|
|
107
|
+
throw new TypeError("option expires must be a Date object");
|
|
108
|
+
}
|
|
109
|
+
str += "; Expires=" + opt.expires.toUTCString();
|
|
110
|
+
}
|
|
111
|
+
if (opt.httpOnly) {
|
|
112
|
+
str += "; HttpOnly";
|
|
113
|
+
}
|
|
114
|
+
if (opt.secure) {
|
|
115
|
+
str += "; Secure";
|
|
116
|
+
}
|
|
117
|
+
if (opt.sameSite) {
|
|
118
|
+
const sameSite = typeof opt.sameSite === "string" ? opt.sameSite.toLowerCase() : opt.sameSite;
|
|
119
|
+
switch (sameSite) {
|
|
120
|
+
case true:
|
|
121
|
+
case "strict":
|
|
122
|
+
str += "; SameSite=Strict";
|
|
123
|
+
break;
|
|
124
|
+
case "lax":
|
|
125
|
+
str += "; SameSite=Lax";
|
|
126
|
+
break;
|
|
127
|
+
default:
|
|
128
|
+
throw new TypeError("option sameSite is invalid");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return str;
|
|
132
|
+
}
|
|
133
|
+
function tryDecode(str, decode) {
|
|
134
|
+
try {
|
|
135
|
+
return decode(str);
|
|
136
|
+
} catch (e) {
|
|
137
|
+
return str;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export {
|
|
141
|
+
Cookies
|
|
142
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
let devBindings;
|
|
2
|
+
function setDevBindings(env) {
|
|
3
|
+
devBindings = env;
|
|
4
|
+
}
|
|
5
|
+
function getDevBindings() {
|
|
6
|
+
return devBindings;
|
|
7
|
+
}
|
|
8
|
+
function clearDevBindingsForTests() {
|
|
9
|
+
devBindings = void 0;
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
clearDevBindingsForTests,
|
|
13
|
+
getDevBindings,
|
|
14
|
+
setDevBindings
|
|
15
|
+
};
|