@skgo/sveltekit-adapter 0.2.7

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.
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Which skgo this adapter is.
3
+ *
4
+ * The adapter writes `skgo.manifest.json` and the Go binary reads it: one
5
+ * contract in two languages, published as one npm package and one Go module at
6
+ * one version. The Go half refuses a manifest written by any adapter but its
7
+ * own, so the manifest has to carry a name for this one.
8
+ *
9
+ * The name is not written down anywhere, because a written-down name is a thing
10
+ * that can be wrong. It is taken from the package's own bytes — the entry vite
11
+ * imports, and every runtime file beside it — the same way, in the same order,
12
+ * as the Go module takes it from the copy it embeds. Two identical fingerprints
13
+ * therefore mean the files really are identical, byte for byte, and a package
14
+ * that lost or gained a file cannot claim to be the one the binary expects.
15
+ */
16
+
17
+ import { createHash } from 'node:crypto';
18
+ import { readdirSync, readFileSync } from 'node:fs';
19
+ import { basename, dirname, join } from 'node:path';
20
+ import { fileURLToPath } from 'node:url';
21
+
22
+ const here = dirname(fileURLToPath(import.meta.url));
23
+
24
+ /** The package root: the directory holding package.json and the entry. */
25
+ const root = dirname(here);
26
+
27
+ /**
28
+ * The runtime directory's name, which is also the entry's name plus `.js` —
29
+ * `skgo-adapter/` beside `skgo-adapter.js`. Reading it off this file's own
30
+ * location rather than writing it twice keeps the two spellings from drifting.
31
+ */
32
+ const dir = basename(here);
33
+
34
+ /**
35
+ * Every runtime file, as a slash-separated path relative to the package root,
36
+ * sorted. Sorted rather than as-read, so the fingerprint is a fact about the
37
+ * bytes and not about the order a directory happened to be listed in.
38
+ *
39
+ * @param {string} at
40
+ * @param {string} prefix
41
+ * @returns {string[]}
42
+ */
43
+ function runtimeFiles(at, prefix) {
44
+ /** @type {string[]} */
45
+ const names = [];
46
+ for (const entry of readdirSync(at, { withFileTypes: true })) {
47
+ const name = prefix + '/' + entry.name;
48
+ if (entry.isDirectory()) {
49
+ names.push(...runtimeFiles(join(at, entry.name), name));
50
+ } else {
51
+ names.push(name);
52
+ }
53
+ }
54
+ return names.sort();
55
+ }
56
+
57
+ /**
58
+ * The identity the manifest carries: the published version of this package, and
59
+ * the fingerprint of the files it is made of.
60
+ *
61
+ * @returns {{ version: string, adapter: string }}
62
+ */
63
+ export function identity() {
64
+ const sum = createHash('sha256');
65
+ sum.update(readFileSync(join(root, dir + '.js')));
66
+ for (const name of runtimeFiles(here, dir)) {
67
+ // The name goes in too, so that moving a file between paths changes the
68
+ // fingerprint even when no byte of it does.
69
+ sum.update(Buffer.from(name + '\0', 'utf-8'));
70
+ sum.update(readFileSync(join(root, name)));
71
+ }
72
+
73
+ const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf-8'));
74
+ return { version: pkg.version, adapter: sum.digest('hex').slice(0, 12) };
75
+ }
@@ -0,0 +1,157 @@
1
+ // The globals kit's runtime and Svelte's renderer reach that a bare
2
+ // ECMAScript engine does not have and Go does not bind.
3
+ //
4
+ // This file is the SSR bundle's banner rather than a module of it. The fold
5
+ // that makes the bundle evaluates kit's shared chunk before the entry, so a
6
+ // polyfill imported as a module would arrive after the code that needs it —
7
+ // which the single-pass build only got away with by module order.
8
+ //
9
+ // URL, URLSearchParams, TextEncoder, TextDecoder, btoa and atob are not here:
10
+ // Go binds those natively when it creates a runtime, before this text runs.
11
+ // What is left is what a Go-backed constructor could not stand in for: the
12
+ // classes kit compares against with `instanceof` (Headers, Blob, File) and the
13
+ // two a render's own `event.fetch` builds and hands back (Request, Response),
14
+ // which are string and Map bookkeeping over a value that never leaves the
15
+ // engine except through `__skgo_fetch`.
16
+
17
+ // Svelte's no-AsyncLocalStorage fallback is gated on exactly this check
18
+ // (svelte/src/internal/server/render-context.js), and kit reads the same flag
19
+ // (kit/src/constants.js) to stop nulling its synchronous request store. It is
20
+ // Svelte's own supported path; the cost is one render per runtime at a time,
21
+ // which the pool in Go pays.
22
+ globalThis.process = { versions: { webcontainer: 'skgo' } };
23
+
24
+ // Headers is reached by kit's own Redirect constructor
25
+ // (exports/internal/shared.js), which builds one to reject a location that
26
+ // could not survive an HTTP header — and does it inside a try/catch, so an
27
+ // absent Headers would be reported as an invalid location rather than as a
28
+ // missing global. Only the construction and the validation it performs are
29
+ // needed; nothing in the engine sends a request.
30
+ if (typeof globalThis.Headers === 'undefined') {
31
+ // RFC 9110 field-name and field-value rules, which is all the real
32
+ // constructor checks that matters here.
33
+ const NAME = /^[A-Za-z0-9!#$%&'*+.^_|~-]+$/;
34
+ const BAD_VALUE = /[\u0000\r\n]/;
35
+
36
+ globalThis.Headers = class Headers {
37
+ constructor(init) {
38
+ this._ = new Map();
39
+ if (init instanceof Headers) {
40
+ for (const [k, v] of init._) this._.set(k, v);
41
+ } else if (Array.isArray(init)) {
42
+ for (const [k, v] of init) this.set(k, v);
43
+ } else if (init && typeof init === 'object') {
44
+ for (const k of Object.keys(init)) this.set(k, init[k]);
45
+ }
46
+ }
47
+ set(name, value) {
48
+ const n = String(name);
49
+ const v = String(value).trim();
50
+ if (!NAME.test(n)) throw new TypeError('Invalid header name: ' + n);
51
+ if (BAD_VALUE.test(v)) throw new TypeError('Invalid header value');
52
+ this._.set(n.toLowerCase(), v);
53
+ }
54
+ append(name, value) {
55
+ const existing = this.get(name);
56
+ this.set(name, existing === null ? value : existing + ', ' + value);
57
+ }
58
+ get(name) {
59
+ const k = String(name).toLowerCase();
60
+ return this._.has(k) ? this._.get(k) : null;
61
+ }
62
+ has(name) {
63
+ return this._.has(String(name).toLowerCase());
64
+ }
65
+ delete(name) {
66
+ this._.delete(String(name).toLowerCase());
67
+ }
68
+ forEach(fn, thisArg) {
69
+ for (const [k, v] of this._) fn.call(thisArg, v, k, this);
70
+ }
71
+ keys() {
72
+ return this._.keys();
73
+ }
74
+ values() {
75
+ return this._.values();
76
+ }
77
+ entries() {
78
+ return this._.entries();
79
+ }
80
+ [Symbol.iterator]() {
81
+ return this._.entries();
82
+ }
83
+ };
84
+ }
85
+
86
+ // Request and Response back a render-time `event.fetch`. Kit's own
87
+ // `normalize_fetch_input` (runtime/server/fetch.js) turns whatever a
88
+ // component passed into a real Request before deciding what to do with it, and
89
+ // the answer a render's fetch gets back has to be a real Response — `await
90
+ // (await event.fetch(...)).json()` is what a page actually writes. Nothing
91
+ // here sends bytes anywhere: building one is string and Map bookkeeping, and
92
+ // the one call that leaves the engine is `__skgo_fetch` itself.
93
+ if (typeof globalThis.Request === 'undefined') {
94
+ globalThis.Request = class Request {
95
+ constructor(input, init = {}) {
96
+ if (input instanceof Request) {
97
+ this.url = input.url;
98
+ this.method = (init.method ?? input.method ?? 'GET').toUpperCase();
99
+ this.headers = init.headers ? new Headers(init.headers) : new Headers(input.headers);
100
+ this._body = init.body !== undefined ? init.body : input._body;
101
+ this.credentials = init.credentials ?? input.credentials ?? 'same-origin';
102
+ this.mode = init.mode ?? input.mode ?? 'cors';
103
+ } else {
104
+ this.url = String(input);
105
+ this.method = (init.method ?? 'GET').toUpperCase();
106
+ this.headers = new Headers(init.headers);
107
+ this._body = init.body;
108
+ this.credentials = init.credentials ?? 'same-origin';
109
+ this.mode = init.mode ?? 'cors';
110
+ }
111
+ }
112
+ async text() { return this._body ?? ''; }
113
+ async json() { return JSON.parse(this._body ?? 'null'); }
114
+ };
115
+ }
116
+
117
+ if (typeof globalThis.Response === 'undefined') {
118
+ globalThis.Response = class Response {
119
+ constructor(body, init = {}) {
120
+ this._body = body ?? '';
121
+ this.status = init.status ?? 200;
122
+ this.statusText = init.statusText ?? '';
123
+ this.headers = init.headers instanceof Headers ? init.headers : new Headers(init.headers);
124
+ this.ok = this.status >= 200 && this.status < 300;
125
+ }
126
+ async text() { return this._body; }
127
+ async json() { return JSON.parse(this._body); }
128
+ async arrayBuffer() { return new TextEncoder().encode(this._body).buffer; }
129
+ clone() {
130
+ return new Response(this._body, { status: this.status, statusText: this.statusText, headers: this.headers });
131
+ }
132
+ };
133
+ }
134
+
135
+ // Blob and File are named by kit's form-field proxy, which asks whether a
136
+ // field's value is a File before it decides how to describe it to the markup.
137
+ // Nothing here ever holds one — an uploaded file's bytes are Go's, and they
138
+ // never enter the engine — so these exist to be compared against.
139
+ if (typeof globalThis.Blob === 'undefined') {
140
+ globalThis.Blob = class Blob {
141
+ constructor(parts = [], options = {}) {
142
+ this._parts = parts;
143
+ this.type = options.type ?? '';
144
+ this.size = 0;
145
+ }
146
+ };
147
+ }
148
+
149
+ if (typeof globalThis.File === 'undefined') {
150
+ globalThis.File = class File extends globalThis.Blob {
151
+ constructor(parts = [], name = '', options = {}) {
152
+ super(parts, options);
153
+ this.name = String(name);
154
+ this.lastModified = options.lastModified ?? 0;
155
+ }
156
+ };
157
+ }