@dreamlake/dreamdb 0.3.0 → 0.4.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 +178 -0
- package/browser/dreamdb.d.ts +326 -0
- package/browser/dreamdb.js +9 -0
- package/{dreamdb_bg.js → browser/dreamdb_bg.js} +612 -2
- package/browser/dreamdb_bg.wasm +0 -0
- package/browser/dreamdb_bg.wasm.d.ts +56 -0
- package/browser-extras.mjs +193 -0
- package/browser.mjs +4 -0
- package/index.d.ts +541 -1
- package/node/dreamdb.cjs +1762 -0
- package/node/dreamdb.d.cts +425 -0
- package/node/dreamdb_bg.wasm +0 -0
- package/node/dreamdb_bg.wasm.d.ts +72 -0
- package/node.cjs +10 -0
- package/node.mjs +19 -0
- package/package.json +40 -16
- package/web/dreamdb.d.ts +407 -0
- package/web/dreamdb.js +1558 -0
- package/web/dreamdb_bg.wasm +0 -0
- package/web/dreamdb_bg.wasm.d.ts +56 -0
- package/web.mjs +17 -0
- package/dreamdb.d.ts +0 -150
- package/dreamdb.js +0 -9
- package/dreamdb_bg.wasm +0 -0
- package/index.js +0 -6
|
Binary file
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const __wbg_s3backend_free: (a: number, b: number) => void;
|
|
5
|
+
export const __wbg_space_free: (a: number, b: number) => void;
|
|
6
|
+
export const __wbg_writer_free: (a: number, b: number) => void;
|
|
7
|
+
export const addressRoundTrip: (a: number, b: number) => [number, number, number, number];
|
|
8
|
+
export const addressVariant: (a: number, b: number) => [number, number, number, number];
|
|
9
|
+
export const bytesToBase32: (a: number, b: number) => [number, number];
|
|
10
|
+
export const decodeCbor: (a: number, b: number) => [number, number, number];
|
|
11
|
+
export const encodeCbor: (a: any) => [number, number, number, number];
|
|
12
|
+
export const modalityParse: (a: number, b: number) => [number, number, number];
|
|
13
|
+
export const multihashBase32: (a: number, b: number) => [number, number];
|
|
14
|
+
export const multihashHex: (a: number, b: number) => [number, number];
|
|
15
|
+
export const rangeHeader: (a: bigint, b: bigint) => [number, number, number, number];
|
|
16
|
+
export const s3backend_get: (a: number, b: number, c: number, d: any) => any;
|
|
17
|
+
export const s3backend_list: (a: number, b: number, c: number) => any;
|
|
18
|
+
export const s3backend_new: (a: number, b: number) => number;
|
|
19
|
+
export const space_connectorBase: (a: number) => [number, number];
|
|
20
|
+
export const space_fromUri: (a: number, b: number, c: any) => any;
|
|
21
|
+
export const space_history: (a: number, b: number) => any;
|
|
22
|
+
export const space_manifestHash: (a: number) => [number, number];
|
|
23
|
+
export const space_queryHybrid: (a: number, b: number, c: number, d: any) => any;
|
|
24
|
+
export const space_queryScalar: (a: number, b: number, c: number, d: number, e: number, f: any) => any;
|
|
25
|
+
export const space_queryText: (a: number, b: number, c: number, d: number, e: number, f: number) => any;
|
|
26
|
+
export const space_queryVector: (a: number, b: number, c: number, d: number, e: number, f: any) => any;
|
|
27
|
+
export const space_readScalarColumn: (a: number, b: any, c: any) => any;
|
|
28
|
+
export const space_resolveObjectIndex: (a: number, b: any) => any;
|
|
29
|
+
export const space_timelineId: (a: number) => [number, number, number, number];
|
|
30
|
+
export const space_trackFor: (a: number, b: number, c: number) => any;
|
|
31
|
+
export const space_tracks: (a: number) => any;
|
|
32
|
+
export const spatialKeyRoundTrip: (a: number, b: number) => [number, number, number, number];
|
|
33
|
+
export const timeAnchorFromHex: (a: number, b: number) => [bigint, number, number];
|
|
34
|
+
export const timeAnchorHex: (a: bigint) => [number, number];
|
|
35
|
+
export const timeBucket: (a: bigint, b: number, c: number) => [bigint, number, number];
|
|
36
|
+
export const version: () => [number, number];
|
|
37
|
+
export const writer_appendMany: (a: number, b: any) => any;
|
|
38
|
+
export const writer_commit: (a: number) => any;
|
|
39
|
+
export const writer_deleteRecords: (a: number, b: number, c: number, d: number, e: number) => any;
|
|
40
|
+
export const writer_manifestHash: (a: number) => [number, number, number, number];
|
|
41
|
+
export const writer_open: (a: number, b: number, c: any) => any;
|
|
42
|
+
export const writer_refName: (a: number) => [number, number];
|
|
43
|
+
export const writer_snapshot: (a: number, b: number, c: number) => any;
|
|
44
|
+
export const zeroSpatialKey: () => [number, number];
|
|
45
|
+
export const __wasm_init: () => void;
|
|
46
|
+
export const wasm_bindgen_f7c54996eb9137d9___convert__closures_____invoke___wasm_bindgen_f7c54996eb9137d9___JsValue__core_7d5f0a2ba6a62c33___result__Result_____wasm_bindgen_f7c54996eb9137d9___JsError___true_: (a: number, b: number, c: any) => [number, number];
|
|
47
|
+
export const wasm_bindgen_f7c54996eb9137d9___convert__closures_____invoke___js_sys_ac40961855821e8e___Function_fn_wasm_bindgen_f7c54996eb9137d9___JsValue_____wasm_bindgen_f7c54996eb9137d9___sys__Undefined___js_sys_ac40961855821e8e___Function_fn_wasm_bindgen_f7c54996eb9137d9___JsValue_____wasm_bindgen_f7c54996eb9137d9___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void;
|
|
48
|
+
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
49
|
+
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
50
|
+
export const __wbindgen_exn_store: (a: number) => void;
|
|
51
|
+
export const __externref_table_alloc: () => number;
|
|
52
|
+
export const __wbindgen_externrefs: WebAssembly.Table;
|
|
53
|
+
export const __wbindgen_destroy_closure: (a: number, b: number) => void;
|
|
54
|
+
export const __externref_table_dealloc: (a: number) => void;
|
|
55
|
+
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
|
56
|
+
export const __wbindgen_start: () => void;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Browser-side additions to the wasm bindings.
|
|
2
|
+
//
|
|
3
|
+
// These live in JS rather than Rust on purpose: they are pure IO plus a
|
|
4
|
+
// user-supplied callback, and the crate itself says so (`connector.rs` keeps
|
|
5
|
+
// URL minting on the JS side). Nothing here touches the protocol, so nothing
|
|
6
|
+
// here can drift from it.
|
|
7
|
+
//
|
|
8
|
+
// Loaded only by the `browser` and `web` entry points. Node does not want a
|
|
9
|
+
// presigned-URL backend — on a server you hand the SDK real credentials via an
|
|
10
|
+
// S3 client, and minting a URL for yourself just adds a round trip.
|
|
11
|
+
|
|
12
|
+
/** Zero spatial-key path segment for non-spatial (fragment) object addresses. */
|
|
13
|
+
export const ZERO_SPATIAL_KEY = '0000000000000000'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Stand-in for the authoring surface, which the browser build does not carry.
|
|
17
|
+
*
|
|
18
|
+
* The type declarations describe `Authoring` on both ends so that a codebase
|
|
19
|
+
* shared between server and client type-checks once. Rather than let the
|
|
20
|
+
* browser fail with `undefined is not a constructor`, every entry point is a
|
|
21
|
+
* function that says what is missing and where to run it.
|
|
22
|
+
*/
|
|
23
|
+
class AuthoringUnavailable {
|
|
24
|
+
static #nope(what) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Authoring.${what} is not available in the browser build of ` +
|
|
27
|
+
`@dreamlake/dreamdb. Dataset creation, layers, merge and compaction ` +
|
|
28
|
+
`pull in the index builders (IVF/IMI/LSH/Vamana + codebook training), ` +
|
|
29
|
+
`which cost ~123 KB gzipped and need training data that does not ` +
|
|
30
|
+
`belong in a tab. Run it under Node — the "node" export condition ` +
|
|
31
|
+
`resolves to the full build — or use the CLI.`,
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
static async create() { AuthoringUnavailable.#nope('create') }
|
|
35
|
+
static async open() { AuthoringUnavailable.#nope('open') }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { AuthoringUnavailable as Authoring }
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A Backend (contract v2) that gets bytes over plain `fetch` and writes through
|
|
42
|
+
* short-lived presigned URLs minted by *your* server.
|
|
43
|
+
*
|
|
44
|
+
* Credentials never reach the browser. That was the explicit constraint, and it
|
|
45
|
+
* is also the only version of browser writes that is safe to ship: a bucket
|
|
46
|
+
* key in client JS is a bucket key in everyone's DevTools.
|
|
47
|
+
*
|
|
48
|
+
* ## What you must provide
|
|
49
|
+
*
|
|
50
|
+
* ```js
|
|
51
|
+
* new PresignedBackend({
|
|
52
|
+
* readBase: 'https://bucket.s3.amazonaws.com', // public/CDN read path
|
|
53
|
+
* mintPut: async (paths, opts) => {
|
|
54
|
+
* // paths: string[] → return { [path]: { url, headers? } }
|
|
55
|
+
* // opts.ifMatch: caller wants a conditional PUT (ref updates only)
|
|
56
|
+
* const r = await fetch('/api/dreamdb/sign', {
|
|
57
|
+
* method: 'POST',
|
|
58
|
+
* headers: { 'content-type': 'application/json' },
|
|
59
|
+
* body: JSON.stringify({ paths, ifMatch: opts?.ifMatch }),
|
|
60
|
+
* })
|
|
61
|
+
* if (!r.ok) throw new Error(`sign failed: ${r.status}`)
|
|
62
|
+
* return (await r.json()).urls
|
|
63
|
+
* },
|
|
64
|
+
* })
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* `mintPut` takes an **array** of paths. One commit writes buckets, tracks, a
|
|
68
|
+
* manifest and a ref; signing them one at a time turns a commit into N server
|
|
69
|
+
* round trips. The backend batches where it can, and signs alone only when a
|
|
70
|
+
* write needs its own conditional header.
|
|
71
|
+
*
|
|
72
|
+
* ## Two things that will bite you if the bucket is misconfigured
|
|
73
|
+
*
|
|
74
|
+
* 1. **`ExposeHeaders: ["ETag"]` in the bucket's CORS rule is mandatory.**
|
|
75
|
+
* Without it the browser can see the response but not its ETag header, so
|
|
76
|
+
* the SDK has no prior version to compare against, falls back to a
|
|
77
|
+
* create-only PUT, and the *second* commit to any ref fails while the first
|
|
78
|
+
* succeeded. That asymmetry is what makes it hard to spot.
|
|
79
|
+
* 2. **Whether `If-Match` survives presigning is provider-specific.** SigV4
|
|
80
|
+
* signs whatever headers you tell it to, so a presigned conditional PUT is
|
|
81
|
+
* constructible — but it is not something the docs promise, and GCS uses
|
|
82
|
+
* `x-goog-if-generation-match` instead. Hence `refStrategy` below.
|
|
83
|
+
*/
|
|
84
|
+
export class PresignedBackend {
|
|
85
|
+
/**
|
|
86
|
+
* @param {object} o
|
|
87
|
+
* @param {string} o.readBase Base URL for reads.
|
|
88
|
+
* @param {(paths: string[], opts?: {ifMatch?: string}) => Promise<Record<string, {url: string, headers?: Record<string,string>}>>} o.mintPut
|
|
89
|
+
* @param {(path: string, opts: {ifMatch?: string, ifNoneMatchStar?: boolean}, bytes: Uint8Array) => Promise<{status: string, etag?: string}>} [o.commitRef]
|
|
90
|
+
* Server-side ref commit. Used when `refStrategy` is `'proxy'`.
|
|
91
|
+
* @param {'proxy'|'presign'} [o.refStrategy='proxy']
|
|
92
|
+
* How the 33-byte ref object is written. `'proxy'` posts it to your
|
|
93
|
+
* server, which performs the conditional PUT with real credentials —
|
|
94
|
+
* works identically on S3, R2, MinIO and GCS. `'presign'` signs a
|
|
95
|
+
* conditional PUT and sends it from the browser; fewer moving parts,
|
|
96
|
+
* but it depends on provider behaviour this SDK cannot promise.
|
|
97
|
+
* @param {(path: string) => string} [o.readUrl] Override read URL building.
|
|
98
|
+
*/
|
|
99
|
+
constructor({ readBase, mintPut, commitRef, refStrategy = 'proxy', readUrl }) {
|
|
100
|
+
if (!readBase) throw new Error('PresignedBackend: readBase is required')
|
|
101
|
+
if (typeof mintPut !== 'function') {
|
|
102
|
+
throw new Error('PresignedBackend: mintPut(paths, opts) is required')
|
|
103
|
+
}
|
|
104
|
+
if (refStrategy === 'proxy' && typeof commitRef !== 'function') {
|
|
105
|
+
throw new Error(
|
|
106
|
+
"PresignedBackend: refStrategy 'proxy' (the default) needs commitRef(). " +
|
|
107
|
+
"Pass refStrategy: 'presign' to sign conditional ref PUTs instead — " +
|
|
108
|
+
'but read the note on provider support first.',
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
this.readBase = readBase.replace(/\/+$/, '')
|
|
112
|
+
this.mintPut = mintPut
|
|
113
|
+
this.commitRef = commitRef
|
|
114
|
+
this.refStrategy = refStrategy
|
|
115
|
+
this._readUrl = readUrl
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#url(path) {
|
|
119
|
+
return this._readUrl ? this._readUrl(path) : `${this.readBase}/${path}`
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** v2 get: returns `{bytes, etag}`. Range is inclusive of `end`. */
|
|
123
|
+
async get(path, range) {
|
|
124
|
+
const headers = {}
|
|
125
|
+
if (range) headers.range = `bytes=${range.start}-${range.end}`
|
|
126
|
+
const r = await fetch(this.#url(path), { headers })
|
|
127
|
+
if (!r.ok) throw new Error(`GET ${path}: ${r.status} ${r.statusText}`)
|
|
128
|
+
return {
|
|
129
|
+
bytes: new Uint8Array(await r.arrayBuffer()),
|
|
130
|
+
etag: normalizeEtag(r.headers.get('etag')),
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async head(path) {
|
|
135
|
+
const r = await fetch(this.#url(path), { method: 'HEAD' })
|
|
136
|
+
if (r.status === 404) return { exists: false }
|
|
137
|
+
if (!r.ok) throw new Error(`HEAD ${path}: ${r.status}`)
|
|
138
|
+
const len = r.headers.get('content-length')
|
|
139
|
+
return {
|
|
140
|
+
exists: true,
|
|
141
|
+
etag: normalizeEtag(r.headers.get('etag')),
|
|
142
|
+
size: len == null ? undefined : Number(len),
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async put(path, bytes, opts = {}) {
|
|
147
|
+
// Ref updates are the only conditional writes, and they are the ones whose
|
|
148
|
+
// semantics differ per provider — so they get their own path.
|
|
149
|
+
const isRef = path.startsWith('refs/')
|
|
150
|
+
if (isRef && this.refStrategy === 'proxy') {
|
|
151
|
+
return await this.commitRef(path, opts, bytes)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const minted = await this.mintPut([path], opts.ifMatch ? { ifMatch: opts.ifMatch } : undefined)
|
|
155
|
+
const spec = minted?.[path]
|
|
156
|
+
if (!spec?.url) throw new Error(`mintPut returned no URL for ${path}`)
|
|
157
|
+
|
|
158
|
+
const headers = { ...(spec.headers || {}) }
|
|
159
|
+
if (opts.ifMatch) headers['if-match'] = opts.ifMatch
|
|
160
|
+
else if (opts.ifNoneMatchStar) headers['if-none-match'] = '*'
|
|
161
|
+
|
|
162
|
+
const r = await fetch(spec.url, { method: 'PUT', body: bytes, headers })
|
|
163
|
+
|
|
164
|
+
// 412 is genuinely ambiguous and the SDK cannot disambiguate it from the
|
|
165
|
+
// status alone: for `If-None-Match: *` on a content-addressed object it
|
|
166
|
+
// means "already there", which is success; for `If-Match` on a ref it means
|
|
167
|
+
// someone else moved it, which is a conflict the caller must resolve.
|
|
168
|
+
if (r.status === 412 || r.status === 409) {
|
|
169
|
+
return opts.ifNoneMatchStar
|
|
170
|
+
? { status: 'exists' }
|
|
171
|
+
: { status: 'casFailed', etag: normalizeEtag(r.headers.get('etag')) }
|
|
172
|
+
}
|
|
173
|
+
if (!r.ok) throw new Error(`PUT ${path}: ${r.status} ${r.statusText}`)
|
|
174
|
+
return { status: 'created', etag: normalizeEtag(r.headers.get('etag')) }
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// No `delete`. It would need a signed DELETE URL, and the sign endpoint only
|
|
178
|
+
// ever signs PUT — handing out object deletion to a browser is not something
|
|
179
|
+
// this write channel should make easy. Nothing in the browser write surface
|
|
180
|
+
// needs it either: `deleteRecords` writes tombstones (new objects), and
|
|
181
|
+
// dropping a ref is an `Authoring` operation, which is Node-only.
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* S3 quotes ETags and sometimes suffixes them (`W/"…"`, `"…-3"` for multipart).
|
|
186
|
+
* The conditional-write comparison is byte-exact, so a stray quote turns every
|
|
187
|
+
* CAS into a mismatch — which reads as "someone else is writing" forever.
|
|
188
|
+
*/
|
|
189
|
+
function normalizeEtag(v) {
|
|
190
|
+
if (!v) return undefined
|
|
191
|
+
const t = v.trim().replace(/^W\//, '').replace(/^"|"$/g, '')
|
|
192
|
+
return t || undefined
|
|
193
|
+
}
|
package/browser.mjs
ADDED