@nats-io/obj 3.0.0-4 → 3.0.0-5
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/package.json +4 -5
- package/build/src/internal_mod.ts +0 -13
- package/build/src/mod.ts +0 -13
- package/build/src/objectstore.ts +0 -922
- package/build/src/types.ts +0 -340
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nats-io/obj",
|
|
3
|
-
"version": "3.0.0-
|
|
3
|
+
"version": "3.0.0-5",
|
|
4
4
|
"files": [
|
|
5
5
|
"lib/",
|
|
6
|
-
"build/src/",
|
|
7
6
|
"LICENSE",
|
|
8
7
|
"README.md"
|
|
9
8
|
],
|
|
@@ -33,8 +32,8 @@
|
|
|
33
32
|
},
|
|
34
33
|
"description": "obj library - this library implements all the base functionality for NATS objectstore for javascript clients",
|
|
35
34
|
"dependencies": {
|
|
36
|
-
"@nats-io/jetstream": "~3.0.0-
|
|
37
|
-
"@nats-io/nats-core": "~3.0.0-
|
|
35
|
+
"@nats-io/jetstream": "~3.0.0-9",
|
|
36
|
+
"@nats-io/nats-core": "~3.0.0-24"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
39
|
"@types/node": "^22.0.0",
|
|
@@ -42,4 +41,4 @@
|
|
|
42
41
|
"typedoc": "^0.26.5",
|
|
43
42
|
"typescript": "^5.5.4"
|
|
44
43
|
}
|
|
45
|
-
}
|
|
44
|
+
}
|
package/build/src/mod.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export type {
|
|
2
|
-
ObjectInfo,
|
|
3
|
-
ObjectResult,
|
|
4
|
-
ObjectStore,
|
|
5
|
-
ObjectStoreLink,
|
|
6
|
-
ObjectStoreMeta,
|
|
7
|
-
ObjectStoreMetaOptions,
|
|
8
|
-
ObjectStoreOptions,
|
|
9
|
-
ObjectStorePutOpts,
|
|
10
|
-
ObjectStoreStatus,
|
|
11
|
-
} from "./internal_mod";
|
|
12
|
-
|
|
13
|
-
export { Objm } from "./objectstore";
|
package/build/src/objectstore.ts
DELETED
|
@@ -1,922 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2022-2024 The NATS Authors
|
|
3
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
* you may not use this file except in compliance with the License.
|
|
5
|
-
* You may obtain a copy of the License at
|
|
6
|
-
*
|
|
7
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
*
|
|
9
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
* See the License for the specific language governing permissions and
|
|
13
|
-
* limitations under the License.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
Base64UrlPaddedCodec,
|
|
18
|
-
DataBuffer,
|
|
19
|
-
deferred,
|
|
20
|
-
Feature,
|
|
21
|
-
headers,
|
|
22
|
-
JSONCodec,
|
|
23
|
-
MsgHdrsImpl,
|
|
24
|
-
nuid,
|
|
25
|
-
QueuedIteratorImpl,
|
|
26
|
-
SHA256,
|
|
27
|
-
} from "@nats-io/nats-core/internal";
|
|
28
|
-
|
|
29
|
-
import type {
|
|
30
|
-
MsgHdrs,
|
|
31
|
-
NatsConnection,
|
|
32
|
-
NatsError,
|
|
33
|
-
QueuedIterator,
|
|
34
|
-
} from "@nats-io/nats-core/internal";
|
|
35
|
-
|
|
36
|
-
import {
|
|
37
|
-
consumerOpts,
|
|
38
|
-
DiscardPolicy,
|
|
39
|
-
JsHeaders,
|
|
40
|
-
ListerImpl,
|
|
41
|
-
PubHeaders,
|
|
42
|
-
StoreCompression,
|
|
43
|
-
toJetStreamClient,
|
|
44
|
-
} from "@nats-io/jetstream/internal";
|
|
45
|
-
|
|
46
|
-
import type {
|
|
47
|
-
JetStreamClient,
|
|
48
|
-
JetStreamClientImpl,
|
|
49
|
-
JetStreamManager,
|
|
50
|
-
JsMsg,
|
|
51
|
-
Lister,
|
|
52
|
-
ListerFieldFilter,
|
|
53
|
-
PubAck,
|
|
54
|
-
PurgeResponse,
|
|
55
|
-
StorageType,
|
|
56
|
-
StreamConfig,
|
|
57
|
-
StreamInfo,
|
|
58
|
-
StreamInfoRequestOptions,
|
|
59
|
-
StreamListResponse,
|
|
60
|
-
} from "@nats-io/jetstream/internal";
|
|
61
|
-
|
|
62
|
-
import type {
|
|
63
|
-
ObjectInfo,
|
|
64
|
-
ObjectResult,
|
|
65
|
-
ObjectStore,
|
|
66
|
-
ObjectStoreMeta,
|
|
67
|
-
ObjectStoreMetaOptions,
|
|
68
|
-
ObjectStoreOptions,
|
|
69
|
-
ObjectStorePutOpts,
|
|
70
|
-
ObjectStoreStatus,
|
|
71
|
-
} from "./types";
|
|
72
|
-
|
|
73
|
-
export const osPrefix = "OBJ_";
|
|
74
|
-
export const digestType = "SHA-256=";
|
|
75
|
-
|
|
76
|
-
export function objectStoreStreamName(bucket: string): string {
|
|
77
|
-
validateBucket(bucket);
|
|
78
|
-
return `${osPrefix}${bucket}`;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function objectStoreBucketName(stream: string): string {
|
|
82
|
-
if (stream.startsWith(osPrefix)) {
|
|
83
|
-
return stream.substring(4);
|
|
84
|
-
}
|
|
85
|
-
return stream;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* The entry point to creating and managing new ObjectStore instances.
|
|
90
|
-
*/
|
|
91
|
-
export class Objm {
|
|
92
|
-
js: JetStreamClientImpl;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Creates an instance of the Objm that allows you to create and access ObjectStore.
|
|
96
|
-
* Note that if the argument is a NatsConnection, default JetStream Options are
|
|
97
|
-
* used. If you want to set some options, please provide a JetStreamClient instead.
|
|
98
|
-
* @param nc
|
|
99
|
-
*/
|
|
100
|
-
constructor(nc: JetStreamClient | NatsConnection) {
|
|
101
|
-
this.js = toJetStreamClient(nc) as JetStreamClientImpl;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Creates and opens the specified ObjectStore. If the Object already exists, it opens the existing ObjectStore.
|
|
106
|
-
* @param name
|
|
107
|
-
* @param opts
|
|
108
|
-
*/
|
|
109
|
-
create(
|
|
110
|
-
name: string,
|
|
111
|
-
opts: Partial<ObjectStoreOptions> = {},
|
|
112
|
-
): Promise<ObjectStore> {
|
|
113
|
-
return this.#maybeCreate(name, opts);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
#maybeCreate(
|
|
117
|
-
name: string,
|
|
118
|
-
opts: Partial<ObjectStoreOptions> = {},
|
|
119
|
-
): Promise<ObjectStore> {
|
|
120
|
-
if (typeof crypto?.subtle?.digest !== "function") {
|
|
121
|
-
return Promise.reject(
|
|
122
|
-
new Error(
|
|
123
|
-
"objectstore: unable to calculate hashes - crypto.subtle.digest with sha256 support is required",
|
|
124
|
-
),
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
const { ok, min } = this.js.nc.features.get(Feature.JS_OBJECTSTORE);
|
|
128
|
-
if (!ok) {
|
|
129
|
-
return Promise.reject(
|
|
130
|
-
new Error(`objectstore is only supported on servers ${min} or better`),
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return ObjectStoreImpl.create(this.js, name, opts);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Returns a list of ObjectStoreInfo for all streams that are identified as
|
|
139
|
-
* being a ObjectStore (that is having names that have the prefix `OBJ_`)
|
|
140
|
-
*/
|
|
141
|
-
list(): Lister<ObjectStoreStatus> {
|
|
142
|
-
const filter: ListerFieldFilter<ObjectStoreStatus> = (
|
|
143
|
-
v: unknown,
|
|
144
|
-
): ObjectStoreStatus[] => {
|
|
145
|
-
const slr = v as StreamListResponse;
|
|
146
|
-
const streams = slr.streams.filter((v) => {
|
|
147
|
-
return v.config.name.startsWith(osPrefix);
|
|
148
|
-
});
|
|
149
|
-
streams.forEach((si) => {
|
|
150
|
-
si.config.sealed = si.config.sealed || false;
|
|
151
|
-
si.config.deny_delete = si.config.deny_delete || false;
|
|
152
|
-
si.config.deny_purge = si.config.deny_purge || false;
|
|
153
|
-
si.config.allow_rollup_hdrs = si.config.allow_rollup_hdrs || false;
|
|
154
|
-
});
|
|
155
|
-
return streams.map((si) => {
|
|
156
|
-
return new ObjectStoreStatusImpl(si);
|
|
157
|
-
});
|
|
158
|
-
};
|
|
159
|
-
const subj = `${this.js.prefix}.STREAM.LIST`;
|
|
160
|
-
return new ListerImpl<ObjectStoreStatus>(subj, filter, this.js);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export class ObjectStoreStatusImpl implements ObjectStoreStatus {
|
|
165
|
-
si: StreamInfo;
|
|
166
|
-
backingStore: string;
|
|
167
|
-
|
|
168
|
-
constructor(si: StreamInfo) {
|
|
169
|
-
this.si = si;
|
|
170
|
-
this.backingStore = "JetStream";
|
|
171
|
-
}
|
|
172
|
-
get bucket(): string {
|
|
173
|
-
return objectStoreBucketName(this.si.config.name);
|
|
174
|
-
}
|
|
175
|
-
get description(): string {
|
|
176
|
-
return this.si.config.description ?? "";
|
|
177
|
-
}
|
|
178
|
-
get ttl(): number {
|
|
179
|
-
return this.si.config.max_age;
|
|
180
|
-
}
|
|
181
|
-
get storage(): StorageType {
|
|
182
|
-
return this.si.config.storage;
|
|
183
|
-
}
|
|
184
|
-
get replicas(): number {
|
|
185
|
-
return this.si.config.num_replicas;
|
|
186
|
-
}
|
|
187
|
-
get sealed(): boolean {
|
|
188
|
-
return this.si.config.sealed;
|
|
189
|
-
}
|
|
190
|
-
get size(): number {
|
|
191
|
-
return this.si.state.bytes;
|
|
192
|
-
}
|
|
193
|
-
get streamInfo(): StreamInfo {
|
|
194
|
-
return this.si;
|
|
195
|
-
}
|
|
196
|
-
get metadata(): Record<string, string> | undefined {
|
|
197
|
-
return this.si.config.metadata;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
get compression(): boolean {
|
|
201
|
-
if (this.si.config.compression) {
|
|
202
|
-
return this.si.config.compression !== StoreCompression.None;
|
|
203
|
-
}
|
|
204
|
-
return false;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
export function validateBucket(name: string) {
|
|
208
|
-
const validBucketRe = /^[-\w]+$/;
|
|
209
|
-
if (!validBucketRe.test(name)) {
|
|
210
|
-
throw new Error(`invalid bucket name: ${name}`);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
export type ServerObjectStoreMeta = {
|
|
215
|
-
name: string;
|
|
216
|
-
description?: string;
|
|
217
|
-
headers?: Record<string, string[]>;
|
|
218
|
-
options?: ObjectStoreMetaOptions;
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
export type ServerObjectInfo = {
|
|
222
|
-
bucket: string;
|
|
223
|
-
nuid: string;
|
|
224
|
-
size: number;
|
|
225
|
-
chunks: number;
|
|
226
|
-
digest: string;
|
|
227
|
-
deleted?: boolean;
|
|
228
|
-
mtime: string;
|
|
229
|
-
revision: number;
|
|
230
|
-
metadata?: Record<string, string>;
|
|
231
|
-
} & ServerObjectStoreMeta;
|
|
232
|
-
|
|
233
|
-
class ObjectInfoImpl implements ObjectInfo {
|
|
234
|
-
info: ServerObjectInfo;
|
|
235
|
-
hdrs!: MsgHdrs;
|
|
236
|
-
constructor(oi: ServerObjectInfo) {
|
|
237
|
-
this.info = oi;
|
|
238
|
-
}
|
|
239
|
-
get name(): string {
|
|
240
|
-
return this.info.name;
|
|
241
|
-
}
|
|
242
|
-
get description(): string {
|
|
243
|
-
return this.info.description ?? "";
|
|
244
|
-
}
|
|
245
|
-
get headers(): MsgHdrs {
|
|
246
|
-
if (!this.hdrs) {
|
|
247
|
-
this.hdrs = MsgHdrsImpl.fromRecord(this.info.headers || {});
|
|
248
|
-
}
|
|
249
|
-
return this.hdrs;
|
|
250
|
-
}
|
|
251
|
-
get options(): ObjectStoreMetaOptions | undefined {
|
|
252
|
-
return this.info.options;
|
|
253
|
-
}
|
|
254
|
-
get bucket(): string {
|
|
255
|
-
return this.info.bucket;
|
|
256
|
-
}
|
|
257
|
-
get chunks(): number {
|
|
258
|
-
return this.info.chunks;
|
|
259
|
-
}
|
|
260
|
-
get deleted(): boolean {
|
|
261
|
-
return this.info.deleted ?? false;
|
|
262
|
-
}
|
|
263
|
-
get digest(): string {
|
|
264
|
-
return this.info.digest;
|
|
265
|
-
}
|
|
266
|
-
get mtime(): string {
|
|
267
|
-
return this.info.mtime;
|
|
268
|
-
}
|
|
269
|
-
get nuid(): string {
|
|
270
|
-
return this.info.nuid;
|
|
271
|
-
}
|
|
272
|
-
get size(): number {
|
|
273
|
-
return this.info.size;
|
|
274
|
-
}
|
|
275
|
-
get revision(): number {
|
|
276
|
-
return this.info.revision;
|
|
277
|
-
}
|
|
278
|
-
get metadata(): Record<string, string> {
|
|
279
|
-
return this.info.metadata || {};
|
|
280
|
-
}
|
|
281
|
-
isLink() {
|
|
282
|
-
return (this.info.options?.link !== undefined) &&
|
|
283
|
-
(this.info.options?.link !== null);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
function toServerObjectStoreMeta(
|
|
288
|
-
meta: Partial<ObjectStoreMeta>,
|
|
289
|
-
): ServerObjectStoreMeta {
|
|
290
|
-
const v = {
|
|
291
|
-
name: meta.name,
|
|
292
|
-
description: meta.description ?? "",
|
|
293
|
-
options: meta.options,
|
|
294
|
-
metadata: meta.metadata,
|
|
295
|
-
} as ServerObjectStoreMeta;
|
|
296
|
-
|
|
297
|
-
if (meta.headers) {
|
|
298
|
-
const mhi = meta.headers as MsgHdrsImpl;
|
|
299
|
-
v.headers = mhi.toRecord();
|
|
300
|
-
}
|
|
301
|
-
return v;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function emptyReadableStream(): ReadableStream {
|
|
305
|
-
return new ReadableStream({
|
|
306
|
-
pull(c) {
|
|
307
|
-
c.enqueue(new Uint8Array(0));
|
|
308
|
-
c.close();
|
|
309
|
-
},
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
export class ObjectStoreImpl implements ObjectStore {
|
|
314
|
-
jsm: JetStreamManager;
|
|
315
|
-
js: JetStreamClient;
|
|
316
|
-
stream!: string;
|
|
317
|
-
name: string;
|
|
318
|
-
|
|
319
|
-
constructor(name: string, jsm: JetStreamManager, js: JetStreamClient) {
|
|
320
|
-
this.name = name;
|
|
321
|
-
this.jsm = jsm;
|
|
322
|
-
this.js = js;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
_checkNotEmpty(name: string): { name: string; error?: Error } {
|
|
326
|
-
if (!name || name.length === 0) {
|
|
327
|
-
return { name, error: new Error("name cannot be empty") };
|
|
328
|
-
}
|
|
329
|
-
return { name };
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async info(name: string): Promise<ObjectInfo | null> {
|
|
333
|
-
const info = await this.rawInfo(name);
|
|
334
|
-
return info ? new ObjectInfoImpl(info) : null;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
async list(): Promise<ObjectInfo[]> {
|
|
338
|
-
const buf: ObjectInfo[] = [];
|
|
339
|
-
const iter = await this.watch({
|
|
340
|
-
ignoreDeletes: true,
|
|
341
|
-
includeHistory: true,
|
|
342
|
-
});
|
|
343
|
-
for await (const info of iter) {
|
|
344
|
-
// watch will give a null when it has initialized
|
|
345
|
-
// for us that is the hint we are done
|
|
346
|
-
if (info === null) {
|
|
347
|
-
break;
|
|
348
|
-
}
|
|
349
|
-
buf.push(info);
|
|
350
|
-
}
|
|
351
|
-
return Promise.resolve(buf);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
async rawInfo(name: string): Promise<ServerObjectInfo | null> {
|
|
355
|
-
const { name: obj, error } = this._checkNotEmpty(name);
|
|
356
|
-
if (error) {
|
|
357
|
-
return Promise.reject(error);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
const meta = this._metaSubject(obj);
|
|
361
|
-
try {
|
|
362
|
-
const m = await this.jsm.streams.getMessage(this.stream, {
|
|
363
|
-
last_by_subj: meta,
|
|
364
|
-
});
|
|
365
|
-
const jc = JSONCodec<ServerObjectInfo>();
|
|
366
|
-
const soi = jc.decode(m.data) as ServerObjectInfo;
|
|
367
|
-
soi.revision = m.seq;
|
|
368
|
-
return soi;
|
|
369
|
-
} catch (err) {
|
|
370
|
-
if (err.code === "404") {
|
|
371
|
-
return null;
|
|
372
|
-
}
|
|
373
|
-
return Promise.reject(err);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
async _si(
|
|
378
|
-
opts?: Partial<StreamInfoRequestOptions>,
|
|
379
|
-
): Promise<StreamInfo | null> {
|
|
380
|
-
try {
|
|
381
|
-
return await this.jsm.streams.info(this.stream, opts);
|
|
382
|
-
} catch (err) {
|
|
383
|
-
const nerr = err as NatsError;
|
|
384
|
-
if (nerr.code === "404") {
|
|
385
|
-
return null;
|
|
386
|
-
}
|
|
387
|
-
return Promise.reject(err);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
async seal(): Promise<ObjectStoreStatus> {
|
|
392
|
-
let info = await this._si();
|
|
393
|
-
if (info === null) {
|
|
394
|
-
return Promise.reject(new Error("object store not found"));
|
|
395
|
-
}
|
|
396
|
-
info.config.sealed = true;
|
|
397
|
-
info = await this.jsm.streams.update(this.stream, info.config);
|
|
398
|
-
return Promise.resolve(new ObjectStoreStatusImpl(info));
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
async status(
|
|
402
|
-
opts?: Partial<StreamInfoRequestOptions>,
|
|
403
|
-
): Promise<ObjectStoreStatus> {
|
|
404
|
-
const info = await this._si(opts);
|
|
405
|
-
if (info === null) {
|
|
406
|
-
return Promise.reject(new Error("object store not found"));
|
|
407
|
-
}
|
|
408
|
-
return Promise.resolve(new ObjectStoreStatusImpl(info));
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
destroy(): Promise<boolean> {
|
|
412
|
-
return this.jsm.streams.delete(this.stream);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
async _put(
|
|
416
|
-
meta: ObjectStoreMeta,
|
|
417
|
-
rs: ReadableStream<Uint8Array> | null,
|
|
418
|
-
opts?: ObjectStorePutOpts,
|
|
419
|
-
): Promise<ObjectInfo> {
|
|
420
|
-
const jsopts = this.js.getOptions();
|
|
421
|
-
opts = opts || { timeout: jsopts.timeout };
|
|
422
|
-
opts.timeout = opts.timeout || jsopts.timeout;
|
|
423
|
-
opts.previousRevision = opts.previousRevision ?? undefined;
|
|
424
|
-
const { timeout, previousRevision } = opts;
|
|
425
|
-
const si = (this.js as unknown as { nc: NatsConnection }).nc.info;
|
|
426
|
-
const maxPayload = si?.max_payload || 1024;
|
|
427
|
-
meta = meta || {} as ObjectStoreMeta;
|
|
428
|
-
meta.options = meta.options || {};
|
|
429
|
-
let maxChunk = meta.options?.max_chunk_size || 128 * 1024;
|
|
430
|
-
maxChunk = maxChunk > maxPayload ? maxPayload : maxChunk;
|
|
431
|
-
meta.options.max_chunk_size = maxChunk;
|
|
432
|
-
|
|
433
|
-
const old = await this.info(meta.name);
|
|
434
|
-
const { name: n, error } = this._checkNotEmpty(meta.name);
|
|
435
|
-
if (error) {
|
|
436
|
-
return Promise.reject(error);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
const id = nuid.next();
|
|
440
|
-
const chunkSubj = this._chunkSubject(id);
|
|
441
|
-
const metaSubj = this._metaSubject(n);
|
|
442
|
-
|
|
443
|
-
const info = Object.assign({
|
|
444
|
-
bucket: this.name,
|
|
445
|
-
nuid: id,
|
|
446
|
-
size: 0,
|
|
447
|
-
chunks: 0,
|
|
448
|
-
}, toServerObjectStoreMeta(meta)) as ServerObjectInfo;
|
|
449
|
-
|
|
450
|
-
const d = deferred<ObjectInfo>();
|
|
451
|
-
|
|
452
|
-
const proms: Promise<unknown>[] = [];
|
|
453
|
-
const db = new DataBuffer();
|
|
454
|
-
try {
|
|
455
|
-
const reader = rs ? rs.getReader() : null;
|
|
456
|
-
const sha = new SHA256();
|
|
457
|
-
|
|
458
|
-
while (true) {
|
|
459
|
-
const { done, value } = reader
|
|
460
|
-
? await reader.read()
|
|
461
|
-
: { done: true, value: undefined };
|
|
462
|
-
if (done) {
|
|
463
|
-
// put any partial chunk in
|
|
464
|
-
if (db.size() > 0) {
|
|
465
|
-
const payload = db.drain();
|
|
466
|
-
sha.update(payload);
|
|
467
|
-
info.chunks!++;
|
|
468
|
-
info.size! += payload.length;
|
|
469
|
-
proms.push(this.js.publish(chunkSubj, payload, { timeout }));
|
|
470
|
-
}
|
|
471
|
-
// wait for all the chunks to write
|
|
472
|
-
await Promise.all(proms);
|
|
473
|
-
proms.length = 0;
|
|
474
|
-
|
|
475
|
-
// prepare the metadata
|
|
476
|
-
info.mtime = new Date().toISOString();
|
|
477
|
-
const digest = sha.digest("base64");
|
|
478
|
-
const pad = digest.length % 3;
|
|
479
|
-
const padding = pad > 0 ? "=".repeat(pad) : "";
|
|
480
|
-
info.digest = `${digestType}${digest}${padding}`;
|
|
481
|
-
info.deleted = false;
|
|
482
|
-
|
|
483
|
-
// trailing md for the object
|
|
484
|
-
const h = headers();
|
|
485
|
-
if (typeof previousRevision === "number") {
|
|
486
|
-
h.set(
|
|
487
|
-
PubHeaders.ExpectedLastSubjectSequenceHdr,
|
|
488
|
-
`${previousRevision}`,
|
|
489
|
-
);
|
|
490
|
-
}
|
|
491
|
-
h.set(JsHeaders.RollupHdr, JsHeaders.RollupValueSubject);
|
|
492
|
-
|
|
493
|
-
// try to update the metadata
|
|
494
|
-
const pa = await this.js.publish(metaSubj, JSONCodec().encode(info), {
|
|
495
|
-
headers: h,
|
|
496
|
-
timeout,
|
|
497
|
-
});
|
|
498
|
-
// update the revision to point to the sequence where we inserted
|
|
499
|
-
info.revision = pa.seq;
|
|
500
|
-
|
|
501
|
-
// if we are here, the new entry is live
|
|
502
|
-
if (old) {
|
|
503
|
-
try {
|
|
504
|
-
await this.jsm.streams.purge(this.stream, {
|
|
505
|
-
filter: `$O.${this.name}.C.${old.nuid}`,
|
|
506
|
-
});
|
|
507
|
-
} catch (_err) {
|
|
508
|
-
// rejecting here, would mean send the wrong signal
|
|
509
|
-
// the update succeeded, but cleanup of old chunks failed.
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// resolve the ObjectInfo
|
|
514
|
-
d.resolve(new ObjectInfoImpl(info!));
|
|
515
|
-
// stop
|
|
516
|
-
break;
|
|
517
|
-
}
|
|
518
|
-
if (value) {
|
|
519
|
-
db.fill(value);
|
|
520
|
-
while (db.size() > maxChunk) {
|
|
521
|
-
info.chunks!++;
|
|
522
|
-
info.size! += maxChunk;
|
|
523
|
-
const payload = db.drain(meta.options.max_chunk_size);
|
|
524
|
-
sha.update(payload);
|
|
525
|
-
proms.push(
|
|
526
|
-
this.js.publish(chunkSubj, payload, { timeout }),
|
|
527
|
-
);
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
} catch (err) {
|
|
532
|
-
// we failed, remove any partials
|
|
533
|
-
await this.jsm.streams.purge(this.stream, { filter: chunkSubj });
|
|
534
|
-
d.reject(err);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
return d;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
putBlob(
|
|
541
|
-
meta: ObjectStoreMeta,
|
|
542
|
-
data: Uint8Array | null,
|
|
543
|
-
opts?: ObjectStorePutOpts,
|
|
544
|
-
): Promise<ObjectInfo> {
|
|
545
|
-
function readableStreamFrom(data: Uint8Array): ReadableStream<Uint8Array> {
|
|
546
|
-
return new ReadableStream<Uint8Array>({
|
|
547
|
-
pull(controller) {
|
|
548
|
-
controller.enqueue(data);
|
|
549
|
-
controller.close();
|
|
550
|
-
},
|
|
551
|
-
});
|
|
552
|
-
}
|
|
553
|
-
if (data === null) {
|
|
554
|
-
data = new Uint8Array(0);
|
|
555
|
-
}
|
|
556
|
-
return this.put(meta, readableStreamFrom(data), opts);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
put(
|
|
560
|
-
meta: ObjectStoreMeta,
|
|
561
|
-
rs: ReadableStream<Uint8Array> | null,
|
|
562
|
-
opts?: ObjectStorePutOpts,
|
|
563
|
-
): Promise<ObjectInfo> {
|
|
564
|
-
if (meta?.options?.link) {
|
|
565
|
-
return Promise.reject(
|
|
566
|
-
new Error("link cannot be set when putting the object in bucket"),
|
|
567
|
-
);
|
|
568
|
-
}
|
|
569
|
-
return this._put(meta, rs, opts);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
async getBlob(name: string): Promise<Uint8Array | null> {
|
|
573
|
-
async function fromReadableStream(
|
|
574
|
-
rs: ReadableStream<Uint8Array>,
|
|
575
|
-
): Promise<Uint8Array> {
|
|
576
|
-
const buf = new DataBuffer();
|
|
577
|
-
const reader = rs.getReader();
|
|
578
|
-
while (true) {
|
|
579
|
-
const { done, value } = await reader.read();
|
|
580
|
-
if (done) {
|
|
581
|
-
return buf.drain();
|
|
582
|
-
}
|
|
583
|
-
if (value && value.length) {
|
|
584
|
-
buf.fill(value);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
const r = await this.get(name);
|
|
590
|
-
if (r === null) {
|
|
591
|
-
return Promise.resolve(null);
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
const vs = await Promise.all([r.error, fromReadableStream(r.data)]);
|
|
595
|
-
if (vs[0]) {
|
|
596
|
-
return Promise.reject(vs[0]);
|
|
597
|
-
} else {
|
|
598
|
-
return Promise.resolve(vs[1]);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
async get(name: string): Promise<ObjectResult | null> {
|
|
603
|
-
const info = await this.rawInfo(name);
|
|
604
|
-
if (info === null) {
|
|
605
|
-
return Promise.resolve(null);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
if (info.deleted) {
|
|
609
|
-
return Promise.resolve(null);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
if (info.options && info.options.link) {
|
|
613
|
-
const ln = info.options.link.name || "";
|
|
614
|
-
if (ln === "") {
|
|
615
|
-
throw new Error("link is a bucket");
|
|
616
|
-
}
|
|
617
|
-
const os = info.options.link.bucket !== this.name
|
|
618
|
-
? await ObjectStoreImpl.create(
|
|
619
|
-
this.js,
|
|
620
|
-
info.options.link.bucket,
|
|
621
|
-
)
|
|
622
|
-
: this;
|
|
623
|
-
return os.get(ln);
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
const d = deferred<Error | null>();
|
|
627
|
-
|
|
628
|
-
const r: Partial<ObjectResult> = {
|
|
629
|
-
info: new ObjectInfoImpl(info),
|
|
630
|
-
error: d,
|
|
631
|
-
};
|
|
632
|
-
if (info.size === 0) {
|
|
633
|
-
r.data = emptyReadableStream();
|
|
634
|
-
d.resolve(null);
|
|
635
|
-
return Promise.resolve(r as ObjectResult);
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
let controller: ReadableStreamDefaultController;
|
|
639
|
-
|
|
640
|
-
const oc = consumerOpts();
|
|
641
|
-
oc.orderedConsumer();
|
|
642
|
-
const sha = new SHA256();
|
|
643
|
-
const subj = `$O.${this.name}.C.${info.nuid}`;
|
|
644
|
-
const sub = await this.js.subscribe(subj, oc);
|
|
645
|
-
(async () => {
|
|
646
|
-
for await (const jm of sub) {
|
|
647
|
-
if (jm.data.length > 0) {
|
|
648
|
-
sha.update(jm.data);
|
|
649
|
-
controller!.enqueue(jm.data);
|
|
650
|
-
}
|
|
651
|
-
if (jm.info.pending === 0) {
|
|
652
|
-
const hash = sha.digest("base64");
|
|
653
|
-
// go pads the hash - which should be multiple of 3 - otherwise pads with '='
|
|
654
|
-
const pad = hash.length % 3;
|
|
655
|
-
const padding = pad > 0 ? "=".repeat(pad) : "";
|
|
656
|
-
const digest = `${digestType}${hash}${padding}`;
|
|
657
|
-
if (digest !== info.digest) {
|
|
658
|
-
controller!.error(
|
|
659
|
-
new Error(
|
|
660
|
-
`received a corrupt object, digests do not match received: ${info.digest} calculated ${digest}`,
|
|
661
|
-
),
|
|
662
|
-
);
|
|
663
|
-
} else {
|
|
664
|
-
controller!.close();
|
|
665
|
-
}
|
|
666
|
-
sub.unsubscribe();
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
})()
|
|
670
|
-
.then(() => {
|
|
671
|
-
d.resolve();
|
|
672
|
-
})
|
|
673
|
-
.catch((err) => {
|
|
674
|
-
controller!.error(err);
|
|
675
|
-
d.reject(err);
|
|
676
|
-
});
|
|
677
|
-
|
|
678
|
-
r.data = new ReadableStream({
|
|
679
|
-
start(c) {
|
|
680
|
-
controller = c;
|
|
681
|
-
},
|
|
682
|
-
cancel() {
|
|
683
|
-
sub.unsubscribe();
|
|
684
|
-
},
|
|
685
|
-
});
|
|
686
|
-
|
|
687
|
-
return r as ObjectResult;
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
linkStore(name: string, bucket: ObjectStore): Promise<ObjectInfo> {
|
|
691
|
-
if (!(bucket instanceof ObjectStoreImpl)) {
|
|
692
|
-
return Promise.reject("bucket required");
|
|
693
|
-
}
|
|
694
|
-
const osi = bucket as ObjectStoreImpl;
|
|
695
|
-
const { name: n, error } = this._checkNotEmpty(name);
|
|
696
|
-
if (error) {
|
|
697
|
-
return Promise.reject(error);
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
const meta = {
|
|
701
|
-
name: n,
|
|
702
|
-
options: { link: { bucket: osi.name } },
|
|
703
|
-
};
|
|
704
|
-
return this._put(meta, null);
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
async link(name: string, info: ObjectInfo): Promise<ObjectInfo> {
|
|
708
|
-
const { name: n, error } = this._checkNotEmpty(name);
|
|
709
|
-
if (error) {
|
|
710
|
-
return Promise.reject(error);
|
|
711
|
-
}
|
|
712
|
-
if (info.deleted) {
|
|
713
|
-
return Promise.reject(new Error("src object is deleted"));
|
|
714
|
-
}
|
|
715
|
-
if ((info as ObjectInfoImpl).isLink()) {
|
|
716
|
-
return Promise.reject(new Error("src object is a link"));
|
|
717
|
-
}
|
|
718
|
-
const dest = await this.rawInfo(name);
|
|
719
|
-
if (dest !== null && !dest.deleted) {
|
|
720
|
-
return Promise.reject(
|
|
721
|
-
new Error("an object already exists with that name"),
|
|
722
|
-
);
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
const link = { bucket: info.bucket, name: info.name };
|
|
726
|
-
const mm = {
|
|
727
|
-
name: n,
|
|
728
|
-
bucket: info.bucket,
|
|
729
|
-
options: { link: link },
|
|
730
|
-
} as ObjectStoreMeta;
|
|
731
|
-
await this.js.publish(this._metaSubject(name), JSON.stringify(mm));
|
|
732
|
-
const i = await this.info(name);
|
|
733
|
-
return Promise.resolve(i!);
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
async delete(name: string): Promise<PurgeResponse> {
|
|
737
|
-
const info = await this.rawInfo(name);
|
|
738
|
-
if (info === null) {
|
|
739
|
-
return Promise.resolve({ purged: 0, success: false });
|
|
740
|
-
}
|
|
741
|
-
info.deleted = true;
|
|
742
|
-
info.size = 0;
|
|
743
|
-
info.chunks = 0;
|
|
744
|
-
info.digest = "";
|
|
745
|
-
|
|
746
|
-
const jc = JSONCodec();
|
|
747
|
-
const h = headers();
|
|
748
|
-
h.set(JsHeaders.RollupHdr, JsHeaders.RollupValueSubject);
|
|
749
|
-
|
|
750
|
-
await this.js.publish(this._metaSubject(info.name), jc.encode(info), {
|
|
751
|
-
headers: h,
|
|
752
|
-
});
|
|
753
|
-
return this.jsm.streams.purge(this.stream, {
|
|
754
|
-
filter: this._chunkSubject(info.nuid),
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
async update(
|
|
759
|
-
name: string,
|
|
760
|
-
meta: Partial<ObjectStoreMeta> = {},
|
|
761
|
-
): Promise<PubAck> {
|
|
762
|
-
const info = await this.rawInfo(name);
|
|
763
|
-
if (info === null) {
|
|
764
|
-
return Promise.reject(new Error("object not found"));
|
|
765
|
-
}
|
|
766
|
-
if (info.deleted) {
|
|
767
|
-
return Promise.reject(
|
|
768
|
-
new Error("cannot update meta for a deleted object"),
|
|
769
|
-
);
|
|
770
|
-
}
|
|
771
|
-
meta.name = meta.name ?? info.name;
|
|
772
|
-
const { name: n, error } = this._checkNotEmpty(meta.name);
|
|
773
|
-
if (error) {
|
|
774
|
-
return Promise.reject(error);
|
|
775
|
-
}
|
|
776
|
-
if (name !== meta.name) {
|
|
777
|
-
const i = await this.info(meta.name);
|
|
778
|
-
if (i && !i.deleted) {
|
|
779
|
-
return Promise.reject(
|
|
780
|
-
new Error("an object already exists with that name"),
|
|
781
|
-
);
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
meta.name = n;
|
|
785
|
-
const ii = Object.assign({}, info, toServerObjectStoreMeta(meta!));
|
|
786
|
-
// if the name changed, delete the old meta
|
|
787
|
-
const ack = await this.js.publish(
|
|
788
|
-
this._metaSubject(ii.name),
|
|
789
|
-
JSON.stringify(ii),
|
|
790
|
-
);
|
|
791
|
-
if (name !== meta.name) {
|
|
792
|
-
await this.jsm.streams.purge(this.stream, {
|
|
793
|
-
filter: this._metaSubject(name),
|
|
794
|
-
});
|
|
795
|
-
}
|
|
796
|
-
return Promise.resolve(ack);
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
async watch(opts: Partial<
|
|
800
|
-
{
|
|
801
|
-
ignoreDeletes?: boolean;
|
|
802
|
-
includeHistory?: boolean;
|
|
803
|
-
}
|
|
804
|
-
> = {}): Promise<QueuedIterator<ObjectInfo | null>> {
|
|
805
|
-
opts.includeHistory = opts.includeHistory ?? false;
|
|
806
|
-
opts.ignoreDeletes = opts.ignoreDeletes ?? false;
|
|
807
|
-
let initialized = false;
|
|
808
|
-
const qi = new QueuedIteratorImpl<ObjectInfo | null>();
|
|
809
|
-
const subj = this._metaSubjectAll();
|
|
810
|
-
try {
|
|
811
|
-
await this.jsm.streams.getMessage(this.stream, { last_by_subj: subj });
|
|
812
|
-
} catch (err) {
|
|
813
|
-
if (err.code === "404") {
|
|
814
|
-
qi.push(null);
|
|
815
|
-
initialized = true;
|
|
816
|
-
} else {
|
|
817
|
-
qi.stop(err);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
const jc = JSONCodec<ObjectInfo>();
|
|
821
|
-
const copts = consumerOpts();
|
|
822
|
-
copts.orderedConsumer();
|
|
823
|
-
if (opts.includeHistory) {
|
|
824
|
-
copts.deliverLastPerSubject();
|
|
825
|
-
} else {
|
|
826
|
-
// FIXME: Go's implementation doesn't seem correct - if history is not desired
|
|
827
|
-
// the watch should only be giving notifications on new entries
|
|
828
|
-
initialized = true;
|
|
829
|
-
copts.deliverNew();
|
|
830
|
-
}
|
|
831
|
-
copts.callback((err: NatsError | null, jm: JsMsg | null) => {
|
|
832
|
-
if (err) {
|
|
833
|
-
qi.stop(err);
|
|
834
|
-
return;
|
|
835
|
-
}
|
|
836
|
-
if (jm !== null) {
|
|
837
|
-
const oi = jc.decode(jm.data);
|
|
838
|
-
if (oi.deleted && opts.ignoreDeletes === true) {
|
|
839
|
-
// do nothing
|
|
840
|
-
} else {
|
|
841
|
-
qi.push(oi);
|
|
842
|
-
}
|
|
843
|
-
if (jm.info?.pending === 0 && !initialized) {
|
|
844
|
-
initialized = true;
|
|
845
|
-
qi.push(null);
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
});
|
|
849
|
-
|
|
850
|
-
const sub = await this.js.subscribe(subj, copts);
|
|
851
|
-
qi._data = sub;
|
|
852
|
-
qi.iterClosed.then(() => {
|
|
853
|
-
sub.unsubscribe();
|
|
854
|
-
});
|
|
855
|
-
sub.closed.then(() => {
|
|
856
|
-
qi.stop();
|
|
857
|
-
}).catch((err) => {
|
|
858
|
-
qi.stop(err);
|
|
859
|
-
});
|
|
860
|
-
|
|
861
|
-
return qi;
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
_chunkSubject(id: string) {
|
|
865
|
-
return `$O.${this.name}.C.${id}`;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
_metaSubject(n: string): string {
|
|
869
|
-
return `$O.${this.name}.M.${Base64UrlPaddedCodec.encode(n)}`;
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
_metaSubjectAll(): string {
|
|
873
|
-
return `$O.${this.name}.M.>`;
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
async init(opts: Partial<ObjectStoreOptions> = {}): Promise<void> {
|
|
877
|
-
try {
|
|
878
|
-
this.stream = objectStoreStreamName(this.name);
|
|
879
|
-
} catch (err) {
|
|
880
|
-
return Promise.reject(err);
|
|
881
|
-
}
|
|
882
|
-
const max_age = opts?.ttl || 0;
|
|
883
|
-
delete opts.ttl;
|
|
884
|
-
// pacify the tsc compiler downstream
|
|
885
|
-
const sc = Object.assign({ max_age }, opts) as unknown as StreamConfig;
|
|
886
|
-
sc.name = this.stream;
|
|
887
|
-
sc.allow_direct = true;
|
|
888
|
-
sc.allow_rollup_hdrs = true;
|
|
889
|
-
sc.discard = DiscardPolicy.New;
|
|
890
|
-
sc.subjects = [`$O.${this.name}.C.>`, `$O.${this.name}.M.>`];
|
|
891
|
-
if (opts.placement) {
|
|
892
|
-
sc.placement = opts.placement;
|
|
893
|
-
}
|
|
894
|
-
if (opts.metadata) {
|
|
895
|
-
sc.metadata = opts.metadata;
|
|
896
|
-
}
|
|
897
|
-
if (typeof opts.compression === "boolean") {
|
|
898
|
-
sc.compression = opts.compression
|
|
899
|
-
? StoreCompression.S2
|
|
900
|
-
: StoreCompression.None;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
try {
|
|
904
|
-
await this.jsm.streams.info(sc.name);
|
|
905
|
-
} catch (err) {
|
|
906
|
-
if (err.message === "stream not found") {
|
|
907
|
-
await this.jsm.streams.add(sc);
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
static async create(
|
|
913
|
-
js: JetStreamClient,
|
|
914
|
-
name: string,
|
|
915
|
-
opts: Partial<ObjectStoreOptions> = {},
|
|
916
|
-
): Promise<ObjectStore> {
|
|
917
|
-
const jsm = await js.jetstreamManager();
|
|
918
|
-
const os = new ObjectStoreImpl(name, jsm, js);
|
|
919
|
-
await os.init(opts);
|
|
920
|
-
return Promise.resolve(os);
|
|
921
|
-
}
|
|
922
|
-
}
|
package/build/src/types.ts
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2023-2024 The NATS Authors
|
|
3
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
* you may not use this file except in compliance with the License.
|
|
5
|
-
* You may obtain a copy of the License at
|
|
6
|
-
*
|
|
7
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
*
|
|
9
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
* See the License for the specific language governing permissions and
|
|
13
|
-
* limitations under the License.
|
|
14
|
-
*/
|
|
15
|
-
import type {
|
|
16
|
-
Placement,
|
|
17
|
-
PubAck,
|
|
18
|
-
PurgeResponse,
|
|
19
|
-
StorageType,
|
|
20
|
-
StreamInfo,
|
|
21
|
-
StreamInfoRequestOptions,
|
|
22
|
-
} from "@nats-io/jetstream";
|
|
23
|
-
import type { MsgHdrs, Nanos, QueuedIterator } from "@nats-io/nats-core";
|
|
24
|
-
|
|
25
|
-
export type ObjectStoreLink = {
|
|
26
|
-
/**
|
|
27
|
-
* name of object store storing the data
|
|
28
|
-
*/
|
|
29
|
-
bucket: string;
|
|
30
|
-
/**
|
|
31
|
-
* link to single object, when empty this means the whole store
|
|
32
|
-
*/
|
|
33
|
-
name?: string;
|
|
34
|
-
};
|
|
35
|
-
export type ObjectStoreMetaOptions = {
|
|
36
|
-
/**
|
|
37
|
-
* If set, the object is a reference to another entry.
|
|
38
|
-
*/
|
|
39
|
-
link?: ObjectStoreLink;
|
|
40
|
-
/**
|
|
41
|
-
* The maximum size in bytes for each chunk.
|
|
42
|
-
* Note that if the size exceeds the maximum size of a stream
|
|
43
|
-
* entry, the number will be clamped to the streams maximum.
|
|
44
|
-
*/
|
|
45
|
-
max_chunk_size?: number;
|
|
46
|
-
};
|
|
47
|
-
export type ObjectStoreMeta = {
|
|
48
|
-
name: string;
|
|
49
|
-
description?: string;
|
|
50
|
-
headers?: MsgHdrs;
|
|
51
|
-
options?: ObjectStoreMetaOptions;
|
|
52
|
-
metadata?: Record<string, string>;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export interface ObjectInfo extends ObjectStoreMeta {
|
|
56
|
-
/**
|
|
57
|
-
* The name of the bucket where the object is stored.
|
|
58
|
-
*/
|
|
59
|
-
bucket: string;
|
|
60
|
-
/**
|
|
61
|
-
* The current ID of the entries holding the data for the object.
|
|
62
|
-
*/
|
|
63
|
-
nuid: string;
|
|
64
|
-
/**
|
|
65
|
-
* The size in bytes of the object.
|
|
66
|
-
*/
|
|
67
|
-
size: number;
|
|
68
|
-
/**
|
|
69
|
-
* The number of entries storing the object.
|
|
70
|
-
*/
|
|
71
|
-
chunks: number;
|
|
72
|
-
/**
|
|
73
|
-
* A cryptographic checksum of the data as a whole.
|
|
74
|
-
*/
|
|
75
|
-
digest: string;
|
|
76
|
-
/**
|
|
77
|
-
* True if the object was deleted.
|
|
78
|
-
*/
|
|
79
|
-
deleted: boolean;
|
|
80
|
-
/**
|
|
81
|
-
* An UTC timestamp
|
|
82
|
-
*/
|
|
83
|
-
mtime: string;
|
|
84
|
-
/**
|
|
85
|
-
* The revision number for the entry
|
|
86
|
-
*/
|
|
87
|
-
revision: number;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* A link reference
|
|
92
|
-
*/
|
|
93
|
-
export interface ObjectLink {
|
|
94
|
-
/**
|
|
95
|
-
* The object store the source data
|
|
96
|
-
*/
|
|
97
|
-
bucket: string;
|
|
98
|
-
/**
|
|
99
|
-
* The name of the entry holding the data. If not
|
|
100
|
-
* set it is a complete object store reference.
|
|
101
|
-
*/
|
|
102
|
-
name?: string;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export type ObjectStoreStatus = {
|
|
106
|
-
/**
|
|
107
|
-
* The bucket name
|
|
108
|
-
*/
|
|
109
|
-
bucket: string;
|
|
110
|
-
/**
|
|
111
|
-
* the description associated with the object store.
|
|
112
|
-
*/
|
|
113
|
-
description: string;
|
|
114
|
-
/**
|
|
115
|
-
* The time to live for entries in the object store in nanoseconds.
|
|
116
|
-
* Convert to millis using the `millis()` function.
|
|
117
|
-
*/
|
|
118
|
-
ttl: Nanos;
|
|
119
|
-
/**
|
|
120
|
-
* The object store's underlying stream storage type.
|
|
121
|
-
*/
|
|
122
|
-
storage: StorageType;
|
|
123
|
-
/**
|
|
124
|
-
* The number of replicas associated with this object store.
|
|
125
|
-
*/
|
|
126
|
-
replicas: number;
|
|
127
|
-
/**
|
|
128
|
-
* Set to true if the object store is sealed and will reject edits.
|
|
129
|
-
*/
|
|
130
|
-
sealed: boolean;
|
|
131
|
-
/**
|
|
132
|
-
* The size in bytes that the object store occupies.
|
|
133
|
-
*/
|
|
134
|
-
size: number;
|
|
135
|
-
/**
|
|
136
|
-
* The underlying storage for the object store. Currently, this always
|
|
137
|
-
* returns "JetStream".
|
|
138
|
-
*/
|
|
139
|
-
backingStore: string;
|
|
140
|
-
/**
|
|
141
|
-
* The StreamInfo backing up the ObjectStore
|
|
142
|
-
*/
|
|
143
|
-
streamInfo: StreamInfo;
|
|
144
|
-
/**
|
|
145
|
-
* Metadata the object store. Note that
|
|
146
|
-
* keys starting with `_nats` are reserved. This feature only supported on servers
|
|
147
|
-
* 2.10.x and better.
|
|
148
|
-
*/
|
|
149
|
-
metadata?: Record<string, string> | undefined;
|
|
150
|
-
/**
|
|
151
|
-
* Compression level of the stream. This feature is only supported in
|
|
152
|
-
* servers 2.10.x and better.
|
|
153
|
-
*/
|
|
154
|
-
compression: boolean;
|
|
155
|
-
};
|
|
156
|
-
/**
|
|
157
|
-
* @deprecated {@link ObjectStoreStatus}
|
|
158
|
-
*/
|
|
159
|
-
export type ObjectStoreInfo = ObjectStoreStatus;
|
|
160
|
-
export type ObjectStoreOptions = {
|
|
161
|
-
/**
|
|
162
|
-
* A description for the object store
|
|
163
|
-
*/
|
|
164
|
-
description?: string;
|
|
165
|
-
/**
|
|
166
|
-
* The time to live for entries in the object store specified
|
|
167
|
-
* as nanoseconds. Use the `nanos()` function to convert millis to
|
|
168
|
-
* nanos.
|
|
169
|
-
*/
|
|
170
|
-
ttl?: Nanos;
|
|
171
|
-
/**
|
|
172
|
-
* The underlying stream storage type for the object store.
|
|
173
|
-
*/
|
|
174
|
-
storage: StorageType;
|
|
175
|
-
/**
|
|
176
|
-
* The number of replicas to create.
|
|
177
|
-
*/
|
|
178
|
-
replicas: number;
|
|
179
|
-
/**
|
|
180
|
-
* The maximum amount of data that the object store should store in bytes.
|
|
181
|
-
*/
|
|
182
|
-
"max_bytes": number;
|
|
183
|
-
/**
|
|
184
|
-
* Placement hints for the underlying object store stream
|
|
185
|
-
*/
|
|
186
|
-
placement: Placement; /**
|
|
187
|
-
* Metadata field to store additional information about the stream. Note that
|
|
188
|
-
* keys starting with `_nats` are reserved. This feature only supported on servers
|
|
189
|
-
* 2.10.x and better.
|
|
190
|
-
*/
|
|
191
|
-
metadata?: Record<string, string>;
|
|
192
|
-
/**
|
|
193
|
-
* Sets the compression level of the stream. This feature is only supported in
|
|
194
|
-
* servers 2.10.x and better.
|
|
195
|
-
*/
|
|
196
|
-
compression?: boolean;
|
|
197
|
-
};
|
|
198
|
-
/**
|
|
199
|
-
* An object that allows reading the object stored under a specified name.
|
|
200
|
-
*/
|
|
201
|
-
export type ObjectResult = {
|
|
202
|
-
/**
|
|
203
|
-
* The info of the object that was retrieved.
|
|
204
|
-
*/
|
|
205
|
-
info: ObjectInfo;
|
|
206
|
-
/**
|
|
207
|
-
* The readable stream where you can read the data.
|
|
208
|
-
*/
|
|
209
|
-
data: ReadableStream<Uint8Array>;
|
|
210
|
-
/**
|
|
211
|
-
* A promise that will resolve to an error if the readable stream failed
|
|
212
|
-
* to process the entire response. Should be checked when the readable stream
|
|
213
|
-
* has finished yielding data.
|
|
214
|
-
*/
|
|
215
|
-
error: Promise<Error | null>;
|
|
216
|
-
};
|
|
217
|
-
export type ObjectStorePutOpts = {
|
|
218
|
-
/**
|
|
219
|
-
* maximum number of millis for the put requests to succeed
|
|
220
|
-
*/
|
|
221
|
-
timeout?: number;
|
|
222
|
-
/**
|
|
223
|
-
* If set the ObjectStore must be at the current sequence or the
|
|
224
|
-
* put will fail. Note the sequence accounts where the metadata
|
|
225
|
-
* for the entry is stored.
|
|
226
|
-
*/
|
|
227
|
-
previousRevision?: number;
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
export interface ObjectStore {
|
|
231
|
-
/**
|
|
232
|
-
* Returns the ObjectInfo of the named entry. Or null if the
|
|
233
|
-
* entry doesn't exist.
|
|
234
|
-
* @param name
|
|
235
|
-
*/
|
|
236
|
-
info(name: string): Promise<ObjectInfo | null>;
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Returns a list of the entries in the ObjectStore
|
|
240
|
-
*/
|
|
241
|
-
list(): Promise<ObjectInfo[]>;
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Returns an object you can use for reading the data from the
|
|
245
|
-
* named stored object or null if the entry doesn't exist.
|
|
246
|
-
* @param name
|
|
247
|
-
*/
|
|
248
|
-
get(name: string): Promise<ObjectResult | null>;
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Returns the data stored for the named entry.
|
|
252
|
-
* @param name
|
|
253
|
-
*/
|
|
254
|
-
getBlob(name: string): Promise<Uint8Array | null>;
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Adds an object to the store with the specified meta
|
|
258
|
-
* and using the specified ReadableStream to stream the data.
|
|
259
|
-
* @param meta
|
|
260
|
-
* @param rs
|
|
261
|
-
* @param opts
|
|
262
|
-
*/
|
|
263
|
-
put(
|
|
264
|
-
meta: ObjectStoreMeta,
|
|
265
|
-
rs: ReadableStream<Uint8Array>,
|
|
266
|
-
opts?: ObjectStorePutOpts,
|
|
267
|
-
): Promise<ObjectInfo>;
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Puts the specified bytes into the store with the specified meta.
|
|
271
|
-
* @param meta
|
|
272
|
-
* @param data
|
|
273
|
-
* @param opts
|
|
274
|
-
*/
|
|
275
|
-
putBlob(
|
|
276
|
-
meta: ObjectStoreMeta,
|
|
277
|
-
data: Uint8Array | null,
|
|
278
|
-
opts?: ObjectStorePutOpts,
|
|
279
|
-
): Promise<ObjectInfo>;
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Deletes the specified entry from the object store.
|
|
283
|
-
* @param name
|
|
284
|
-
*/
|
|
285
|
-
delete(name: string): Promise<PurgeResponse>;
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Adds a link to another object in the same store or a different one.
|
|
289
|
-
* Note that links of links are rejected.
|
|
290
|
-
* object.
|
|
291
|
-
* @param name
|
|
292
|
-
* @param meta
|
|
293
|
-
*/
|
|
294
|
-
link(name: string, meta: ObjectInfo): Promise<ObjectInfo>;
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Add a link to another object store
|
|
298
|
-
* @param name
|
|
299
|
-
* @param bucket
|
|
300
|
-
*/
|
|
301
|
-
linkStore(name: string, bucket: ObjectStore): Promise<ObjectInfo>;
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Watch an object store and receive updates of modifications via
|
|
305
|
-
* an iterator.
|
|
306
|
-
* @param opts
|
|
307
|
-
*/
|
|
308
|
-
watch(
|
|
309
|
-
opts?: Partial<
|
|
310
|
-
{
|
|
311
|
-
ignoreDeletes?: boolean;
|
|
312
|
-
includeHistory?: boolean;
|
|
313
|
-
}
|
|
314
|
-
>,
|
|
315
|
-
): Promise<QueuedIterator<ObjectInfo | null>>;
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Seals the object store preventing any further modifications.
|
|
319
|
-
*/
|
|
320
|
-
seal(): Promise<ObjectStoreStatus>;
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Returns the runtime status of the object store.
|
|
324
|
-
* @param opts
|
|
325
|
-
*/
|
|
326
|
-
status(opts?: Partial<StreamInfoRequestOptions>): Promise<ObjectStoreStatus>;
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Update the metadata for an object. If the name is modified, the object
|
|
330
|
-
* is effectively renamed and will only be accessible by its new name.
|
|
331
|
-
* @param name
|
|
332
|
-
* @param meta
|
|
333
|
-
*/
|
|
334
|
-
update(name: string, meta: Partial<ObjectStoreMeta>): Promise<PubAck>;
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Destroys the object store and all its entries.
|
|
338
|
-
*/
|
|
339
|
-
destroy(): Promise<boolean>;
|
|
340
|
-
}
|