sdocs-dev 1.1.2 → 1.2.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/bin/sdocs-dev.js +22 -6
- package/package.json +4 -1
- package/public/brotli-wasm.js +519 -0
- package/public/brotli_wasm_bg.wasm +0 -0
- package/public/default.md +3 -3
- package/public/images/examples.png +0 -0
- package/public/index.html +1 -0
- package/public/sdocs-app.js +17 -19
- package/public/sw.js +2 -0
- package/server.js +1 -0
package/bin/sdocs-dev.js
CHANGED
|
@@ -249,21 +249,37 @@ EXAMPLE — editorial article with colored heading tiers
|
|
|
249
249
|
---
|
|
250
250
|
`;
|
|
251
251
|
|
|
252
|
-
// ── Compression (
|
|
252
|
+
// ── Compression (brotli + base64url) ─────────────────
|
|
253
253
|
|
|
254
|
-
function
|
|
255
|
-
|
|
256
|
-
return deflated.toString('base64')
|
|
254
|
+
function toBase64Url(buf) {
|
|
255
|
+
return Buffer.from(buf).toString('base64')
|
|
257
256
|
.replace(/\+/g, '-')
|
|
258
257
|
.replace(/\//g, '_')
|
|
259
258
|
.replace(/=+$/, '');
|
|
260
259
|
}
|
|
261
260
|
|
|
262
|
-
function
|
|
261
|
+
function fromBase64Url(b64url) {
|
|
263
262
|
let b64 = b64url.replace(/-/g, '+').replace(/_/g, '/');
|
|
264
263
|
const pad = (4 - b64.length % 4) % 4;
|
|
265
264
|
b64 += '='.repeat(pad);
|
|
266
|
-
return
|
|
265
|
+
return Buffer.from(b64, 'base64');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function compressToBase64Url(text) {
|
|
269
|
+
const compressed = zlib.brotliCompressSync(Buffer.from(text, 'utf-8'), {
|
|
270
|
+
params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 11 }
|
|
271
|
+
});
|
|
272
|
+
return toBase64Url(compressed);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function decompressFromBase64Url(b64url) {
|
|
276
|
+
const buf = fromBase64Url(b64url);
|
|
277
|
+
// Try brotli first, fall back to deflate for old URLs
|
|
278
|
+
try {
|
|
279
|
+
return zlib.brotliDecompressSync(buf).toString('utf-8');
|
|
280
|
+
} catch (_) {
|
|
281
|
+
return zlib.inflateRawSync(buf).toString('utf-8');
|
|
282
|
+
}
|
|
267
283
|
}
|
|
268
284
|
|
|
269
285
|
// ── Slugify ───────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sdocs-dev",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Open, share, and style markdown files from the terminal",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"bin": {
|
|
@@ -32,6 +32,9 @@
|
|
|
32
32
|
},
|
|
33
33
|
"homepage": "https://sdocs.dev",
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"brotli": "^1.3.3",
|
|
36
|
+
"brotli-dec-wasm": "^2.3.2",
|
|
37
|
+
"brotli-wasm": "^3.0.1",
|
|
35
38
|
"marked": "^11.0.0"
|
|
36
39
|
},
|
|
37
40
|
"devDependencies": {
|
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
// brotli-wasm IIFE wrapper (auto-generated from brotli-wasm npm package)
|
|
2
|
+
// Provides window.BrotliWasm.ready (Promise), .compress(Uint8Array), .decompress(Uint8Array)
|
|
3
|
+
(function() {
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
let wasm;
|
|
8
|
+
|
|
9
|
+
const heap = new Array(32).fill(undefined);
|
|
10
|
+
|
|
11
|
+
heap.push(undefined, null, true, false);
|
|
12
|
+
|
|
13
|
+
function getObject(idx) { return heap[idx]; }
|
|
14
|
+
|
|
15
|
+
const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
16
|
+
|
|
17
|
+
cachedTextDecoder.decode();
|
|
18
|
+
|
|
19
|
+
let cachegetUint8Memory0 = null;
|
|
20
|
+
function getUint8Memory0() {
|
|
21
|
+
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
|
|
22
|
+
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
|
|
23
|
+
}
|
|
24
|
+
return cachegetUint8Memory0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getStringFromWasm0(ptr, len) {
|
|
28
|
+
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let heap_next = heap.length;
|
|
32
|
+
|
|
33
|
+
function addHeapObject(obj) {
|
|
34
|
+
if (heap_next === heap.length) heap.push(heap.length + 1);
|
|
35
|
+
const idx = heap_next;
|
|
36
|
+
heap_next = heap[idx];
|
|
37
|
+
|
|
38
|
+
heap[idx] = obj;
|
|
39
|
+
return idx;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let WASM_VECTOR_LEN = 0;
|
|
43
|
+
|
|
44
|
+
const cachedTextEncoder = new TextEncoder('utf-8');
|
|
45
|
+
|
|
46
|
+
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
|
|
47
|
+
? function (arg, view) {
|
|
48
|
+
return cachedTextEncoder.encodeInto(arg, view);
|
|
49
|
+
}
|
|
50
|
+
: function (arg, view) {
|
|
51
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
52
|
+
view.set(buf);
|
|
53
|
+
return {
|
|
54
|
+
read: arg.length,
|
|
55
|
+
written: buf.length
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
60
|
+
|
|
61
|
+
if (realloc === undefined) {
|
|
62
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
63
|
+
const ptr = malloc(buf.length);
|
|
64
|
+
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
65
|
+
WASM_VECTOR_LEN = buf.length;
|
|
66
|
+
return ptr;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let len = arg.length;
|
|
70
|
+
let ptr = malloc(len);
|
|
71
|
+
|
|
72
|
+
const mem = getUint8Memory0();
|
|
73
|
+
|
|
74
|
+
let offset = 0;
|
|
75
|
+
|
|
76
|
+
for (; offset < len; offset++) {
|
|
77
|
+
const code = arg.charCodeAt(offset);
|
|
78
|
+
if (code > 0x7F) break;
|
|
79
|
+
mem[ptr + offset] = code;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (offset !== len) {
|
|
83
|
+
if (offset !== 0) {
|
|
84
|
+
arg = arg.slice(offset);
|
|
85
|
+
}
|
|
86
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3);
|
|
87
|
+
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
|
|
88
|
+
const ret = encodeString(arg, view);
|
|
89
|
+
|
|
90
|
+
offset += ret.written;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
WASM_VECTOR_LEN = offset;
|
|
94
|
+
return ptr;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let cachegetInt32Memory0 = null;
|
|
98
|
+
function getInt32Memory0() {
|
|
99
|
+
if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
|
|
100
|
+
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
|
|
101
|
+
}
|
|
102
|
+
return cachegetInt32Memory0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function dropObject(idx) {
|
|
106
|
+
if (idx < 36) return;
|
|
107
|
+
heap[idx] = heap_next;
|
|
108
|
+
heap_next = idx;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function takeObject(idx) {
|
|
112
|
+
const ret = getObject(idx);
|
|
113
|
+
dropObject(idx);
|
|
114
|
+
return ret;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function passArray8ToWasm0(arg, malloc) {
|
|
118
|
+
const ptr = malloc(arg.length * 1);
|
|
119
|
+
getUint8Memory0().set(arg, ptr / 1);
|
|
120
|
+
WASM_VECTOR_LEN = arg.length;
|
|
121
|
+
return ptr;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let stack_pointer = 32;
|
|
125
|
+
|
|
126
|
+
function addBorrowedObject(obj) {
|
|
127
|
+
if (stack_pointer == 1) throw new Error('out of js stack');
|
|
128
|
+
heap[--stack_pointer] = obj;
|
|
129
|
+
return stack_pointer;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function getArrayU8FromWasm0(ptr, len) {
|
|
133
|
+
return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* @param {Uint8Array} buf
|
|
137
|
+
* @param {any} raw_options
|
|
138
|
+
* @returns {Uint8Array}
|
|
139
|
+
*/
|
|
140
|
+
function compress(buf, raw_options) {
|
|
141
|
+
try {
|
|
142
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
143
|
+
const ptr0 = passArray8ToWasm0(buf, wasm.__wbindgen_malloc);
|
|
144
|
+
const len0 = WASM_VECTOR_LEN;
|
|
145
|
+
wasm.compress(retptr, ptr0, len0, addBorrowedObject(raw_options));
|
|
146
|
+
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
|
147
|
+
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
|
148
|
+
var r2 = getInt32Memory0()[retptr / 4 + 2];
|
|
149
|
+
var r3 = getInt32Memory0()[retptr / 4 + 3];
|
|
150
|
+
if (r3) {
|
|
151
|
+
throw takeObject(r2);
|
|
152
|
+
}
|
|
153
|
+
var v1 = getArrayU8FromWasm0(r0, r1).slice();
|
|
154
|
+
wasm.__wbindgen_free(r0, r1 * 1);
|
|
155
|
+
return v1;
|
|
156
|
+
} finally {
|
|
157
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
158
|
+
heap[stack_pointer++] = undefined;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* @param {Uint8Array} buf
|
|
164
|
+
* @returns {Uint8Array}
|
|
165
|
+
*/
|
|
166
|
+
function decompress(buf) {
|
|
167
|
+
try {
|
|
168
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
169
|
+
const ptr0 = passArray8ToWasm0(buf, wasm.__wbindgen_malloc);
|
|
170
|
+
const len0 = WASM_VECTOR_LEN;
|
|
171
|
+
wasm.decompress(retptr, ptr0, len0);
|
|
172
|
+
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
|
173
|
+
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
|
174
|
+
var r2 = getInt32Memory0()[retptr / 4 + 2];
|
|
175
|
+
var r3 = getInt32Memory0()[retptr / 4 + 3];
|
|
176
|
+
if (r3) {
|
|
177
|
+
throw takeObject(r2);
|
|
178
|
+
}
|
|
179
|
+
var v1 = getArrayU8FromWasm0(r0, r1).slice();
|
|
180
|
+
wasm.__wbindgen_free(r0, r1 * 1);
|
|
181
|
+
return v1;
|
|
182
|
+
} finally {
|
|
183
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function isLikeNone(x) {
|
|
188
|
+
return x === undefined || x === null;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Same as [`brotli::BrotliResult`] except [`brotli::BrotliResult::ResultFailure`].
|
|
192
|
+
*
|
|
193
|
+
* Always `> 0`.
|
|
194
|
+
*
|
|
195
|
+
* `ResultFailure` is removed
|
|
196
|
+
* because we will convert the failure to an actual negative error code (if available) and pass it elsewhere.
|
|
197
|
+
*/
|
|
198
|
+
export const BrotliStreamResultCode = Object.freeze({ ResultSuccess:1,"1":"ResultSuccess",NeedsMoreInput:2,"2":"NeedsMoreInput",NeedsMoreOutput:3,"3":"NeedsMoreOutput", });
|
|
199
|
+
/**
|
|
200
|
+
* Returned by every successful (de)compression.
|
|
201
|
+
*/
|
|
202
|
+
export class BrotliStreamResult {
|
|
203
|
+
|
|
204
|
+
static __wrap(ptr) {
|
|
205
|
+
const obj = Object.create(BrotliStreamResult.prototype);
|
|
206
|
+
obj.ptr = ptr;
|
|
207
|
+
|
|
208
|
+
return obj;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
__destroy_into_raw() {
|
|
212
|
+
const ptr = this.ptr;
|
|
213
|
+
this.ptr = 0;
|
|
214
|
+
|
|
215
|
+
return ptr;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
free() {
|
|
219
|
+
const ptr = this.__destroy_into_raw();
|
|
220
|
+
wasm.__wbg_brotlistreamresult_free(ptr);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Result code.
|
|
224
|
+
*
|
|
225
|
+
* See [`BrotliStreamResultCode`] for available values.
|
|
226
|
+
*
|
|
227
|
+
* When error, the error code is not passed here but rather goes to `Err`.
|
|
228
|
+
*/
|
|
229
|
+
get code() {
|
|
230
|
+
const ret = wasm.__wbg_get_brotlistreamresult_code(this.ptr);
|
|
231
|
+
return ret >>> 0;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Result code.
|
|
235
|
+
*
|
|
236
|
+
* See [`BrotliStreamResultCode`] for available values.
|
|
237
|
+
*
|
|
238
|
+
* When error, the error code is not passed here but rather goes to `Err`.
|
|
239
|
+
* @param {number} arg0
|
|
240
|
+
*/
|
|
241
|
+
set code(arg0) {
|
|
242
|
+
wasm.__wbg_set_brotlistreamresult_code(this.ptr, arg0);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Output buffer
|
|
246
|
+
*/
|
|
247
|
+
get buf() {
|
|
248
|
+
try {
|
|
249
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
250
|
+
wasm.__wbg_get_brotlistreamresult_buf(retptr, this.ptr);
|
|
251
|
+
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
|
252
|
+
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
|
253
|
+
var v0 = getArrayU8FromWasm0(r0, r1).slice();
|
|
254
|
+
wasm.__wbindgen_free(r0, r1 * 1);
|
|
255
|
+
return v0;
|
|
256
|
+
} finally {
|
|
257
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Output buffer
|
|
262
|
+
* @param {Uint8Array} arg0
|
|
263
|
+
*/
|
|
264
|
+
set buf(arg0) {
|
|
265
|
+
const ptr0 = passArray8ToWasm0(arg0, wasm.__wbindgen_malloc);
|
|
266
|
+
const len0 = WASM_VECTOR_LEN;
|
|
267
|
+
wasm.__wbg_set_brotlistreamresult_buf(this.ptr, ptr0, len0);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Consumed bytes of the input buffer
|
|
271
|
+
*/
|
|
272
|
+
get input_offset() {
|
|
273
|
+
const ret = wasm.__wbg_get_brotlistreamresult_input_offset(this.ptr);
|
|
274
|
+
return ret >>> 0;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Consumed bytes of the input buffer
|
|
278
|
+
* @param {number} arg0
|
|
279
|
+
*/
|
|
280
|
+
set input_offset(arg0) {
|
|
281
|
+
wasm.__wbg_set_brotlistreamresult_input_offset(this.ptr, arg0);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
*/
|
|
286
|
+
export class CompressStream {
|
|
287
|
+
|
|
288
|
+
static __wrap(ptr) {
|
|
289
|
+
const obj = Object.create(CompressStream.prototype);
|
|
290
|
+
obj.ptr = ptr;
|
|
291
|
+
|
|
292
|
+
return obj;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
__destroy_into_raw() {
|
|
296
|
+
const ptr = this.ptr;
|
|
297
|
+
this.ptr = 0;
|
|
298
|
+
|
|
299
|
+
return ptr;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
free() {
|
|
303
|
+
const ptr = this.__destroy_into_raw();
|
|
304
|
+
wasm.__wbg_compressstream_free(ptr);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* @param {number | undefined} quality
|
|
308
|
+
*/
|
|
309
|
+
constructor(quality) {
|
|
310
|
+
const ret = wasm.compressstream_new(!isLikeNone(quality), isLikeNone(quality) ? 0 : quality);
|
|
311
|
+
return CompressStream.__wrap(ret);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* @param {Uint8Array | undefined} input_opt
|
|
315
|
+
* @param {number} output_size
|
|
316
|
+
* @returns {BrotliStreamResult}
|
|
317
|
+
*/
|
|
318
|
+
compress(input_opt, output_size) {
|
|
319
|
+
try {
|
|
320
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
321
|
+
var ptr0 = isLikeNone(input_opt) ? 0 : passArray8ToWasm0(input_opt, wasm.__wbindgen_malloc);
|
|
322
|
+
var len0 = WASM_VECTOR_LEN;
|
|
323
|
+
wasm.compressstream_compress(retptr, this.ptr, ptr0, len0, output_size);
|
|
324
|
+
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
|
325
|
+
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
|
326
|
+
var r2 = getInt32Memory0()[retptr / 4 + 2];
|
|
327
|
+
if (r2) {
|
|
328
|
+
throw takeObject(r1);
|
|
329
|
+
}
|
|
330
|
+
return BrotliStreamResult.__wrap(r0);
|
|
331
|
+
} finally {
|
|
332
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* @returns {number}
|
|
337
|
+
*/
|
|
338
|
+
total_out() {
|
|
339
|
+
const ret = wasm.compressstream_total_out(this.ptr);
|
|
340
|
+
return ret >>> 0;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
*/
|
|
345
|
+
export class DecompressStream {
|
|
346
|
+
|
|
347
|
+
static __wrap(ptr) {
|
|
348
|
+
const obj = Object.create(DecompressStream.prototype);
|
|
349
|
+
obj.ptr = ptr;
|
|
350
|
+
|
|
351
|
+
return obj;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
__destroy_into_raw() {
|
|
355
|
+
const ptr = this.ptr;
|
|
356
|
+
this.ptr = 0;
|
|
357
|
+
|
|
358
|
+
return ptr;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
free() {
|
|
362
|
+
const ptr = this.__destroy_into_raw();
|
|
363
|
+
wasm.__wbg_decompressstream_free(ptr);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
*/
|
|
367
|
+
constructor() {
|
|
368
|
+
const ret = wasm.decompressstream_new();
|
|
369
|
+
return DecompressStream.__wrap(ret);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* @param {Uint8Array} input
|
|
373
|
+
* @param {number} output_size
|
|
374
|
+
* @returns {BrotliStreamResult}
|
|
375
|
+
*/
|
|
376
|
+
decompress(input, output_size) {
|
|
377
|
+
try {
|
|
378
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
379
|
+
const ptr0 = passArray8ToWasm0(input, wasm.__wbindgen_malloc);
|
|
380
|
+
const len0 = WASM_VECTOR_LEN;
|
|
381
|
+
wasm.decompressstream_decompress(retptr, this.ptr, ptr0, len0, output_size);
|
|
382
|
+
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
|
383
|
+
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
|
384
|
+
var r2 = getInt32Memory0()[retptr / 4 + 2];
|
|
385
|
+
if (r2) {
|
|
386
|
+
throw takeObject(r1);
|
|
387
|
+
}
|
|
388
|
+
return BrotliStreamResult.__wrap(r0);
|
|
389
|
+
} finally {
|
|
390
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* @returns {number}
|
|
395
|
+
*/
|
|
396
|
+
total_out() {
|
|
397
|
+
const ret = wasm.decompressstream_total_out(this.ptr);
|
|
398
|
+
return ret >>> 0;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
async function load(module, imports) {
|
|
403
|
+
if (typeof Response === 'function' && module instanceof Response) {
|
|
404
|
+
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
|
405
|
+
try {
|
|
406
|
+
return await WebAssembly.instantiateStreaming(module, imports);
|
|
407
|
+
|
|
408
|
+
} catch (e) {
|
|
409
|
+
if (module.headers.get('Content-Type') != 'application/wasm') {
|
|
410
|
+
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
|
411
|
+
|
|
412
|
+
} else {
|
|
413
|
+
throw e;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const bytes = await module.arrayBuffer();
|
|
419
|
+
return await WebAssembly.instantiate(bytes, imports);
|
|
420
|
+
|
|
421
|
+
} else {
|
|
422
|
+
const instance = await WebAssembly.instantiate(module, imports);
|
|
423
|
+
|
|
424
|
+
if (instance instanceof WebAssembly.Instance) {
|
|
425
|
+
return { instance, module };
|
|
426
|
+
|
|
427
|
+
} else {
|
|
428
|
+
return instance;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
async function init(input) {
|
|
434
|
+
if (typeof input === 'undefined') {
|
|
435
|
+
input = new URL('brotli_wasm_bg.wasm', import.meta.url);
|
|
436
|
+
}
|
|
437
|
+
const imports = {};
|
|
438
|
+
imports.wbg = {};
|
|
439
|
+
imports.wbg.__wbindgen_is_undefined = function(arg0) {
|
|
440
|
+
const ret = getObject(arg0) === undefined;
|
|
441
|
+
return ret;
|
|
442
|
+
};
|
|
443
|
+
imports.wbg.__wbindgen_is_object = function(arg0) {
|
|
444
|
+
const val = getObject(arg0);
|
|
445
|
+
const ret = typeof(val) === 'object' && val !== null;
|
|
446
|
+
return ret;
|
|
447
|
+
};
|
|
448
|
+
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
|
|
449
|
+
const ret = getStringFromWasm0(arg0, arg1);
|
|
450
|
+
return addHeapObject(ret);
|
|
451
|
+
};
|
|
452
|
+
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
|
|
453
|
+
const ret = new Error(getStringFromWasm0(arg0, arg1));
|
|
454
|
+
return addHeapObject(ret);
|
|
455
|
+
};
|
|
456
|
+
imports.wbg.__wbindgen_json_serialize = function(arg0, arg1) {
|
|
457
|
+
const obj = getObject(arg1);
|
|
458
|
+
const ret = JSON.stringify(obj === undefined ? null : obj);
|
|
459
|
+
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
460
|
+
const len0 = WASM_VECTOR_LEN;
|
|
461
|
+
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
|
462
|
+
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
|
463
|
+
};
|
|
464
|
+
imports.wbg.__wbg_new_693216e109162396 = function() {
|
|
465
|
+
const ret = new Error();
|
|
466
|
+
return addHeapObject(ret);
|
|
467
|
+
};
|
|
468
|
+
imports.wbg.__wbg_stack_0ddaca5d1abfb52f = function(arg0, arg1) {
|
|
469
|
+
const ret = getObject(arg1).stack;
|
|
470
|
+
const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
471
|
+
const len0 = WASM_VECTOR_LEN;
|
|
472
|
+
getInt32Memory0()[arg0 / 4 + 1] = len0;
|
|
473
|
+
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
|
|
474
|
+
};
|
|
475
|
+
imports.wbg.__wbg_error_09919627ac0992f5 = function(arg0, arg1) {
|
|
476
|
+
try {
|
|
477
|
+
console.error(getStringFromWasm0(arg0, arg1));
|
|
478
|
+
} finally {
|
|
479
|
+
wasm.__wbindgen_free(arg0, arg1);
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
|
|
483
|
+
takeObject(arg0);
|
|
484
|
+
};
|
|
485
|
+
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
|
|
486
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
|
|
490
|
+
input = fetch(input);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
const { instance, module } = await load(await input, imports);
|
|
496
|
+
|
|
497
|
+
wasm = instance.exports;
|
|
498
|
+
init.__wbindgen_wasm_module = module;
|
|
499
|
+
|
|
500
|
+
return wasm;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
// Auto-init: fetch WASM from same directory
|
|
508
|
+
var wasmUrl = '/public/brotli_wasm_bg.wasm';
|
|
509
|
+
window.BrotliWasm = {
|
|
510
|
+
ready: init(wasmUrl).then(function() {
|
|
511
|
+
window.BrotliWasm.compress = compress;
|
|
512
|
+
window.BrotliWasm.decompress = decompress;
|
|
513
|
+
return window.BrotliWasm;
|
|
514
|
+
}),
|
|
515
|
+
compress: function() { throw new Error('BrotliWasm not ready'); },
|
|
516
|
+
decompress: function() { throw new Error('BrotliWasm not ready'); },
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
})();
|
|
Binary file
|
package/public/default.md
CHANGED
|
@@ -23,7 +23,7 @@ But while markdown is great for agents, it's a bit annoying for humans. Quickly
|
|
|
23
23
|
|
|
24
24
|
SmallDocs is an [open source](https://github.com/JoshInLisbon/SDocs) attempt at something different. It lets you (or your agent) easily, elegantly and <ins>100% privately</ins> **read**, **format**, **share** and **export** `.md` files.
|
|
25
25
|
|
|
26
|
-
Reading a `.md` file in SmallDocs feels just like this (you're reading markdown right now). And by playing with the styles, it can feel like [this](https://sdocs.dev/#md=
|
|
26
|
+
Reading a `.md` file in SmallDocs feels just like this (you're reading markdown right now). And by playing with the styles, it can feel like [this](https://sdocs.dev/#md=jZTdbuNGDIXv9RQHykWBrS1Ijp04LlAgSRF021wEmwC5piRKM_BoqJ0ZxdAWBfoQfcI-STFSfnc3Re8MknN4-JHycrlMgg6Gd0jvFOPcBUiDWyMHfGKqtW3TxIfRsN8lQCM2XFGnzbhDei2O0gQoyfOV2HCrv_AOxTYBjLb8K-tWhR2K7CwBFFPNzu_wx1uRG0NjQ9rhF-17Q2O6gK8o-imyYoGOXKvthYQg3Q55tsGfUax40pl7rrL1HF-9jRfZ6RTvY_itVJEdTymj7T5ma67EUdBid0itWE6ndGmk2n8eJHAsKsXV7O51HdQO68WrTnl2tnnUi0MnQORS7Vsng613SI8aak6aPJ0ylRhxMbiqVutiOwdfEXrOb8v1pjierbx4fU5Tvlmt6qf097xePpXWazo9oXTxtasNN3ySLl40T8oNrflJs5J6Vnv7KudtXb1-dUrrZlXNr2py--8RKLigYv0VAc7rTbV-n8Cj7_cI8LZab-l_EdiWJ2fF-hsCK1qtiu3rWcotbc_y_ybw7asXo8vlMkmO8M7nlCQfLQgHcaaG9EF3-gvXaMTB73XXadsuEBQ7hvYgfB40Bzgu2ZjpOt2sA2_kYMYsSY6OcK9G3PbMNX7XxnhcStc7Vmy9FpskPyN97I5mcFZ7xT72QKdtDbFmxEEHhY4CO03GR9N7KwfDdcs_QYfoJSht91EjKAroaM8eh_jzwJMpyOB8luKfv_7Gb6IsrqXac5JEEPTAjlpGz86Lnco9Vps8cqh9DEcvQ-BsnmP5NGUVRdmjd9JpzygWeZ7_mOFiiFA8k6sUKrFe-8A2mBFeycHPHksexdY4yXMc-i4u6xUW1E56jyCwTA5f2MkM8045Ztw4qoKu2MfYEYoMn3hyNYHryVHrqFdJcsGNOEYnD9Gv2MUMQwdQS9pm0yF4rqKTnryH4weOjCd2UazRzgeIjfvwnutsbrnKcO7agefdxEIaghKXJB8bjDKA2mh0yvIDuzEuqF3E1A-OYSU830pcyWOYSi-u1LbNcDN4Nd11hnO_x4eDGj889j7OcGnE89S2FNnPayzZv4gq6nu2HtQEdpMhH6TPcM3zWLpm8vAcguEM906HyZSazlAcyELJ4Gbo57jSlgzulAytCnO7hnyIHQ80xj0NNv49BLI1vHQ8K-lpha1-4Ig86I6z5F8&theme=light), [this](https://sdocs.dev/#md=jVTtbtpIFP0_T3Fl1D8RNh4DDvaPlfJBdiO1aupktdKqUhg81zDFnqEzYxJaKu1D7BP2Saqx8YbQZlsLieGce-85Plzb931ihS0xBe_s5hoyLFCjzBE2kUeM3ZZoUgJQKGmvWCXKbQrerap1jnDLpIGhRwDmzOCVkvZWfMIU6JgAlELiHygWS5sCDWIHLZFx1CaFz8_HZWqurPL6UDG9EPJcWauqFMJgCF9cG-062vFRi0bPURqMWnx4jNNxQ6wdfqyQNFSuOHZdKXhXQjN4o6TyGnZeqnz1sVa2qZkrzVH_JbhdphD1D5S6aaUw1lWaNcuFXDiCjvsgJEfZhBHty1w2BMDFl68WWtWSp-D1iubyGiZXpdIOjEZREu3Bgxz_4ymjGI1aw034q2d0mMQJZx3d3e-RblxMCub1n7qS8XAShl3Xj3K4OBLo_3RmPI75adzO5EyvfpRAyCmlp0cJ5AmnPHk5gSIs4iJ_MYHxhMVF8f8J0JjOo-jQbVGweHz6SwnsBY4T-H7mZJ6MEnQzfd8npAfHzx0h58wg_Jm9TmG2tHZt0sGArUWAj6xalxjkqhpsohkhvR6c1XaJ0oqcWaEkIWdlCRo_1misaQ5CIzA4R6ZRg1UrlCAk2CXCzPUqLT41rbN9qikhs9mMPOPSrt-s7kuxwfsgCJoq52Aq-VoJaY371YObt7d3MOAqrytswAuNzDoPEh-gw4NG5YNRknwmAF7zDvJS8N7VTFvU5RYyXCttvb6jC6UrZh1fMb3i6kG2eK6kRdkQPXhHIUNTl9a8l-9lhhuUNcJC4wNEw1dBEHjkS-v65CRDs1bS4MkJfP3nX5hFIYXWKJ8dWRPcjecqv588Rquk2Cu3xfetqyiMYj8c-jS5o2Eaus_fbV2tS1fw8t_4FNXgQKNz6hL9fXoY6CAVnJAMrRa4cbF2DMy3cH0ZEPIbZC7wUlTCvW_C8Gkh1qihErK22Bzd5q1wG7Q6l9PX07vpd1I3qCsmUdpyCxxLtGgOVAO4WwoDLHd7AjmTUlmYI9SSK4lBuyFaKw0XiqMhZNccYAdvkEkhF7AjO7-59l_uRHYwCkPYwbXcsFLw7g5grvgWWpq6GcIYN0NpEPvKdsXbkhHs4LKLxxkr3GPZklECu4OgAB9zRI6O_QY&theme=dark) or even [this](https://sdocs.dev/#md=jVRLbtxGEN3zFA-jhQFBQ8yM9Z1FANmAEBt2spAAxcsiu0h2ptlFdxc1mQQBcohcwuscwTfJSYJuzsSSP0GWrGpW1ftUzefzQq06XmN2z7xhb2A93thYiZ8VUXeO47oAGvF6Q711uzVmP4zeqswKoKLIN-L11v7KaywvCsBZz9-zbTtdY1lenhVAx2Q4xDV-e1rntURurMct-Tg7QawpDbIsF2cn6Cm01r8QVenXWJSnZ_g9lVoeqkwtV-X5FF89jS_38SGFn9ZalqucqpzUm_ejKKc3lQTD4d4a7dY4O3lUalFeTb1dBlUACXe9aYOM3qwxO2qapmrOZjlTi5OQgiuzulqdT8FHBPybrxfPr1bVLFfOrG2epFdXl4vq6pD-2qwvD0_54rR-Xs9OPp_KNKtmMTv5VPOiOa_OF4eatZip2tO_LpsFXz7-6_GghsLmawwsaXm-PP2MAb7khbn8NgP7ub_FwJkhw6v_xcB-xM8ZWNFqtXrCQLWgxdXlfzPw5V-fBp3P50VxhC9WpSjuusAMQ7tY4geBVes5UNiVeD1GBaG2uoN2pAi8pWAituQNB-vbsiiOjnATrKEd_v7jT1y7hnoqinsGhWAfOLfSjuFIGdQoBy_iQd5gS27DBlEDJYPCepX8VpzhqPBpGSsJnYgpcddxesqsERQYFQV2O2ytYbCXse3QSIBuBQPL4LjEGxq9CTt05NuIinXL7FGN1hnr21jihoygH6OtYYJtNEJGhTSQgT2MSIhlUXyHdzLCiH-meLDR6h5mmeMtK5zEND6snmRkia1nMWMZxHotJ0aU0QbrXAJNwVjPEZQoHhzVjK3VhGEMUKpcynkDL-jZjxN-2XoOqEJCq9h2pPzAAVuKaALHbtLjlnQMB0VesPv4oU8yM3oJ3voWUSkom6nh8fFAUT9-sBGG4Unp-DhNlYZvqJcxoqINJ0O843iS4-9HHjm3deLbfcJqjmwlaAebMKeerzl8_MvbXiLeiqeoHHawEVTFMRi3Q8U0qm1Gl8dNeHaIY2gSIzWFvYXekh85XWgYVrKuxD0jDuw1K97JGDLfgTNrtYzOoKOH5Bnascm8ZnqOJieNPrJmWfY2pAQlo0u-Ddh78U5CSE33RCZm2uRPn3tOsuT7Ch2DZzMh0C7xvKXQ53GiNFriFVRkg9MLDJ2oxBI_-onFNjl80m70B-Xe_IQbqlXCriiuUYt_4Kya9WaMGiw51NIPjn9BMzoHadZFMccLkU3sZIiTvFX6TCTUCWTjRDK0mq2zvi3muEYQaVSGtFGQBw5OZGP3XFTBmpaLOW7z6oGCQvxeJnog65JVD4IVc7yUpmGe7gXVOpJzO2jS3cDZDaPODzLYxN1dZuq6Sot3OEmv0vJ4UWjY5UEEth8Cx4idjCVy_ud0nY4rtr49frJ1aS3Q04ZjsmRPrWe19aRUHca-crmmdcnfNZmDqW0_SIw2wemsc_vopC0pzoc-y-LFczoRVpON6zGQsnk80-OL2dEwsI8JQcWfrF4WxatnzuUY1Zuy-Ac&theme=light):
|
|
27
27
|
|
|
28
28
|

|
|
29
29
|
|
|
@@ -46,7 +46,7 @@ https://sdocs.dev/#md={compressed & encoded .md}
|
|
|
46
46
|
|
|
47
47
|
Your entire document (content and styles) lives in the URL hash.
|
|
48
48
|
|
|
49
|
-
To keep URLs as short as possible, SmallDocs compresses your markdown using [deflate](https://en.wikipedia.org/wiki/Deflate) (a standard compression algorithm built into every browser) and then encodes the result with [base64url](https://en.wikipedia.org/wiki/Base64#URL_applications) (a URL-safe variant of base64 that avoids characters like `+`, `/`, and `=` which would otherwise need percent-encoding).
|
|
49
|
+
To keep URLs as short as possible, SmallDocs compresses your markdown using [deflate](https://en.wikipedia.org/wiki/Deflate) (a standard compression algorithm built into every browser) and then encodes the result with [base64url](https://en.wikipedia.org/wiki/Base64#URL_applications) (a URL-safe variant of base64 that avoids characters like `+`, `/`, and `=` which would otherwise need percent-encoding). Style properties that match built-in defaults (e.g. `fontFamily: Inter`, `baseFontSize: 16`) are omitted from the URL — only values that differ from defaults are included, which keeps URLs shorter.
|
|
50
50
|
|
|
51
51
|
The `mode` parameter controls which view opens. Valid values are `read` (clean reading view, style panel hidden), `style` (style panel visible), and `raw` (raw markdown editor). When sharing a link for someone to read, use `mode=read`:
|
|
52
52
|
|
|
@@ -62,7 +62,7 @@ https://sdocs.dev/#md=...&sec=url-formatting
|
|
|
62
62
|
|
|
63
63
|
The `sec` value is the heading text slugified (lowercased, spaces become hyphens, special characters stripped). The page will scroll to that section on load.
|
|
64
64
|
|
|
65
|
-
The `theme` parameter forces a specific theme: `theme=light` or `theme=dark`. This
|
|
65
|
+
The `theme` parameter forces a specific theme: `theme=light` or `theme=dark`. This is useful when sharing a link where the document looks best in a particular theme. The override is view-only — it applies for that view but won't change the reader's saved theme preference.
|
|
66
66
|
|
|
67
67
|
### Privacy
|
|
68
68
|
|
|
Binary file
|
package/public/index.html
CHANGED
package/public/sdocs-app.js
CHANGED
|
@@ -197,7 +197,7 @@ function loadText(text, filename) {
|
|
|
197
197
|
syncAll('load');
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
// ── Compression helpers (
|
|
200
|
+
// ── Compression helpers (brotli + base64url) ──
|
|
201
201
|
|
|
202
202
|
function toBase64Url(bytes) {
|
|
203
203
|
var bin = Array.from(new Uint8Array(bytes), function(b) { return String.fromCharCode(b); }).join('');
|
|
@@ -213,27 +213,13 @@ function fromBase64Url(str) {
|
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
async function compressText(text) {
|
|
216
|
+
await BrotliWasm.ready;
|
|
216
217
|
var encoded = new TextEncoder().encode(text);
|
|
217
|
-
var
|
|
218
|
-
|
|
219
|
-
writer.write(encoded);
|
|
220
|
-
writer.close();
|
|
221
|
-
var chunks = [];
|
|
222
|
-
var reader = cs.readable.getReader();
|
|
223
|
-
while (true) {
|
|
224
|
-
var result = await reader.read();
|
|
225
|
-
if (result.done) break;
|
|
226
|
-
chunks.push(result.value);
|
|
227
|
-
}
|
|
228
|
-
var total = chunks.reduce(function(n, c) { return n + c.length; }, 0);
|
|
229
|
-
var buf = new Uint8Array(total);
|
|
230
|
-
var offset = 0;
|
|
231
|
-
for (var i = 0; i < chunks.length; i++) { buf.set(chunks[i], offset); offset += chunks[i].length; }
|
|
232
|
-
return toBase64Url(buf);
|
|
218
|
+
var compressed = BrotliWasm.compress(encoded, { quality: 11 });
|
|
219
|
+
return toBase64Url(compressed);
|
|
233
220
|
}
|
|
234
221
|
|
|
235
|
-
async function
|
|
236
|
-
var bytes = fromBase64Url(b64url);
|
|
222
|
+
async function decompressDeflate(bytes) {
|
|
237
223
|
var ds = new DecompressionStream('deflate-raw');
|
|
238
224
|
var writer = ds.writable.getWriter();
|
|
239
225
|
writer.write(bytes);
|
|
@@ -252,6 +238,18 @@ async function decompressText(b64url) {
|
|
|
252
238
|
return new TextDecoder().decode(buf);
|
|
253
239
|
}
|
|
254
240
|
|
|
241
|
+
async function decompressText(b64url) {
|
|
242
|
+
await BrotliWasm.ready;
|
|
243
|
+
var bytes = fromBase64Url(b64url);
|
|
244
|
+
// Try brotli first, fall back to deflate for old URLs
|
|
245
|
+
try {
|
|
246
|
+
var decompressed = BrotliWasm.decompress(bytes);
|
|
247
|
+
return new TextDecoder().decode(decompressed);
|
|
248
|
+
} catch (_) {
|
|
249
|
+
return decompressDeflate(bytes);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
255
253
|
// ── Auto-save to URL hash ──────────────────────────
|
|
256
254
|
|
|
257
255
|
function updateHash() {
|
package/public/sw.js
CHANGED