Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@travetto/model

Package Overview
Dependencies
Maintainers
0
Versions
371
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@travetto/model - npm Package Compare versions

Comparing version 4.1.3 to 5.0.0-rc.0

14

package.json
{
"name": "@travetto/model",
"version": "4.1.3",
"version": "5.0.0-rc.0",
"description": "Datastore abstraction for core operations.",

@@ -29,10 +29,10 @@ "keywords": [

"dependencies": {
"@travetto/config": "^4.1.1",
"@travetto/di": "^4.1.1",
"@travetto/registry": "^4.1.1",
"@travetto/schema": "^4.1.1"
"@travetto/config": "^5.0.0-rc.0",
"@travetto/di": "^5.0.0-rc.0",
"@travetto/registry": "^5.0.0-rc.0",
"@travetto/schema": "^5.0.0-rc.0"
},
"peerDependencies": {
"@travetto/cli": "^4.1.1",
"@travetto/test": "^4.1.1"
"@travetto/cli": "^5.0.0-rc.0",
"@travetto/test": "^5.0.0-rc.0"
},

@@ -39,0 +39,0 @@ "peerDependenciesMeta": {

@@ -175,11 +175,5 @@ <!-- This file was generated by @travetto/doc and should not be modified directly -->

*/
getStream(location: string): Promise<Readable>;
getStream(location: string, range?: StreamRange): Promise<Readable>;
/**
* Get partial stream from asset store given a starting byte and an optional ending byte
* @param location The location of the stream
*/
getStreamPartial(location: string, start: number, end?: number): Promise<PartialStream>;
/**
* Get metadata for stream

@@ -235,3 +229,3 @@ * @param location The location of the stream

|[SQL Model Service](https://github.com/travetto/travetto/tree/main/module/model-sql#readme "SQL backing for the travetto model module, with real-time modeling support for SQL schemas.")|X|X|X|X| |X|
|[MemoryModelService](https://github.com/travetto/travetto/tree/main/module/model/src/provider/memory.ts#L53)|X|X|X|X|X|X|
|[MemoryModelService](https://github.com/travetto/travetto/tree/main/module/model/src/provider/memory.ts#L54)|X|X|X|X|X|X|
|[FileModelService](https://github.com/travetto/travetto/tree/main/module/model/src/provider/file.ts#L50)|X|X| |X|X|X|

@@ -245,3 +239,4 @@

import { Readable } from 'node:stream';
import { StreamUtil, Class, TimeSpan } from '@travetto/base';
import { buffer as toBuffer } from 'node:stream/consumers';
import { Class, TimeSpan } from '@travetto/base';
import { DeepPartial } from '@travetto/schema';

@@ -251,3 +246,3 @@ import { Injectable } from '@travetto/di';

import { ModelCrudSupport } from '../service/crud';
import { ModelStreamSupport, PartialStream, StreamMeta } from '../service/stream';
import { ModelStreamSupport, StreamMeta, StreamRange } from '../service/stream';
import { ModelType, OptionalId } from '../types/model';

@@ -264,3 +259,3 @@ import { ModelExpirySupport } from '../service/expiry';

import { ModelStorageUtil } from '../internal/service/storage';
import { ModelStreamUtil, StreamModel, STREAMS } from '../internal/service/stream';
import { enforceRange, StreamModel, STREAMS } from '../internal/service/stream';
import { IndexConfig } from '../registry/types';

@@ -271,3 +266,3 @@ const STREAM_META = `${STREAMS}_meta`;

export class MemoryModelConfig {
autoCreate?: boolean;
autoCreate?: boolean = true;
namespace?: string;

@@ -310,4 +305,3 @@ cullRate?: number | TimeSpan;

async upsertStream(location: string, input: Readable, meta: StreamMeta): Promise<void>;
async getStream(location: string): Promise<Readable>;
async getStreamPartial(location: string, start: number, end?: number): Promise<PartialStream>;
async getStream(location: string, range?: StreamRange): Promise<Readable>;
async describeStream(location: string): Promise<StreamMeta>;

@@ -314,0 +308,0 @@ async deleteStream(location: string): Promise<void>;

import crypto from 'node:crypto';
import { Class, ObjectUtil, Util } from '@travetto/base';
import { SchemaRegistry, SchemaValidator, ValidationError, ValidationResultError } from '@travetto/schema';
import { Class, Util } from '@travetto/base';
import { DataUtil, SchemaRegistry, SchemaValidator, ValidationError, ValidationResultError } from '@travetto/schema';

@@ -80,3 +80,3 @@ import { ModelRegistry } from '../../registry/model';

if (ObjectUtil.isPlainObject(item)) {
if (DataUtil.isPlainObject(item)) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions

@@ -122,3 +122,3 @@ item = cls.from(item as object);

static async naivePartialUpdate<T extends ModelType>(cls: Class<T>, item: Partial<T>, view: undefined | string, getExisting: () => Promise<T>): Promise<T> {
if (ObjectUtil.isPlainObject(item)) {
if (DataUtil.isPlainObject(item)) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions

@@ -125,0 +125,0 @@ item = cls.from(item as object);

@@ -37,3 +37,3 @@ import { ShutdownManager, Class, TimeSpan, TimeUtil, Util } from '@travetto/base';

const running = new AbortController();
const cullInterval = TimeUtil.timeToMs(svc.config?.cullRate ?? '10m');
const cullInterval = TimeUtil.asMillis(svc.config?.cullRate ?? '10m');

@@ -40,0 +40,0 @@ ShutdownManager.onGracefulShutdown(async () => running.abort(), this);

@@ -1,6 +0,22 @@

import { Class } from '@travetto/base';
import { AppError, Class } from '@travetto/base';
import { ModelType } from '../../types/model';
import { StreamRange } from '../../service/stream';
class Cls { id: string; }
export const StreamModel: Class<ModelType> = Cls;
export const STREAMS = '_streams';
export const STREAMS = '_streams';
/**
* Enforce byte range for stream stream/file of a certain size
*/
export function enforceRange({ start, end }: StreamRange, size: number): Required<StreamRange> {
end = Math.min(end ?? size - 1, size - 1);
if (Number.isNaN(start) || Number.isNaN(end) || !Number.isFinite(start) || start >= size || start < 0 || start > end) {
throw new AppError('Invalid position, out of range', 'data');
}
return { start, end };
}
import fs from 'node:fs/promises';
import { createReadStream } from 'node:fs';
import { createReadStream, createWriteStream } from 'node:fs';
import os from 'node:os';
import { Readable } from 'node:stream';
import { pipeline } from 'node:stream/promises';
import path from 'node:path';
import { path, RuntimeContext } from '@travetto/manifest';
import { StreamUtil, Class, TimeSpan } from '@travetto/base';
import { RuntimeContext } from '@travetto/manifest';
import { Class, TimeSpan } from '@travetto/base';
import { Injectable } from '@travetto/di';

@@ -15,3 +15,3 @@ import { Config } from '@travetto/config';

import { ModelCrudSupport } from '../service/crud';
import { ModelStreamSupport, PartialStream, StreamMeta } from '../service/stream';
import { ModelStreamSupport, StreamMeta, StreamRange } from '../service/stream';
import { ModelType, OptionalId } from '../types/model';

@@ -25,3 +25,3 @@ import { ModelExpirySupport } from '../service/expiry';

import { ExistsError } from '../error/exists';
import { StreamModel, STREAMS } from '../internal/service/stream';
import { enforceRange, StreamModel, STREAMS } from '../internal/service/stream';

@@ -117,3 +117,3 @@ type Suffix = '.bin' | '.meta' | '.json' | '.expires';

if (await exists(file)) {
const content = await StreamUtil.streamToBuffer(createReadStream(file));
const content = await fs.readFile(file);
return this.checkExpiry(cls, await ModelCrudUtil.load(cls, content));

@@ -186,3 +186,3 @@ }

await Promise.all([
StreamUtil.writeToFile(input, file),
await pipeline(input, createWriteStream(file)),
fs.writeFile(file.replace(BIN, META), JSON.stringify(meta), 'utf8')

@@ -192,20 +192,14 @@ ]);

async getStream(location: string): Promise<Readable> {
async getStream(location: string, range?: StreamRange): Promise<Readable> {
const file = await this.#find(STREAMS, BIN, location);
return createReadStream(file);
if (range) {
const meta = await this.describeStream(location);
range = enforceRange(range, meta.size);
}
return createReadStream(file, range);
}
async getStreamPartial(location: string, start: number, end?: number): Promise<PartialStream> {
const file = await this.#find(STREAMS, BIN, location);
const meta = await this.describeStream(location);
[start, end] = StreamUtil.enforceRange(start, end, meta.size);
const stream = createReadStream(file, { start, end });
return { stream, range: [start, end] };
}
async describeStream(location: string): Promise<StreamMeta> {
const file = await this.#find(STREAMS, META, location);
const content = await StreamUtil.streamToBuffer(createReadStream(file));
const content = await fs.readFile(file);
const text: StreamMeta = JSON.parse(content.toString('utf8'));

@@ -212,0 +206,0 @@ return text;

import { Readable } from 'node:stream';
import { buffer as toBuffer } from 'node:stream/consumers';
import { StreamUtil, Class, TimeSpan } from '@travetto/base';
import { Class, TimeSpan } from '@travetto/base';
import { DeepPartial } from '@travetto/schema';

@@ -9,3 +10,3 @@ import { Injectable } from '@travetto/di';

import { ModelCrudSupport } from '../service/crud';
import { ModelStreamSupport, PartialStream, StreamMeta } from '../service/stream';
import { ModelStreamSupport, StreamMeta, StreamRange } from '../service/stream';
import { ModelType, OptionalId } from '../types/model';

@@ -22,3 +23,3 @@ import { ModelExpirySupport } from '../service/expiry';

import { ModelStorageUtil } from '../internal/service/storage';
import { StreamModel, STREAMS } from '../internal/service/stream';
import { enforceRange, StreamModel, STREAMS } from '../internal/service/stream';
import { IndexConfig } from '../registry/types';

@@ -249,20 +250,15 @@

metaContent.set(location, Buffer.from(JSON.stringify(meta)));
streams.set(location, await StreamUtil.streamToBuffer(input));
streams.set(location, await toBuffer(input));
}
async getStream(location: string): Promise<Readable> {
async getStream(location: string, range?: StreamRange): Promise<Readable> {
const streams = this.#find(STREAMS, location, 'notfound');
return StreamUtil.bufferToStream(streams.get(location)!);
let buffer = streams.get(location)!;
if (range) {
range = enforceRange(range, buffer.length);
buffer = buffer.subarray(range.start, range.end! + 1);
}
return Readable.from(buffer);
}
async getStreamPartial(location: string, start: number, end?: number): Promise<PartialStream> {
const streams = this.#find(STREAMS, location, 'notfound');
const buffer = streams.get(location)!;
[start, end] = StreamUtil.enforceRange(start, end, buffer.length);
const stream = await StreamUtil.bufferToStream(buffer.subarray(start, end + 1));
return { stream, range: [start, end] };
}
async describeStream(location: string): Promise<StreamMeta> {

@@ -269,0 +265,0 @@ const metaContent = this.#find(STREAM_META, location, 'notfound');

@@ -1,2 +0,3 @@

import { Primitive, Class } from '@travetto/base';
import { Class } from '@travetto/base';
import { Primitive } from '@travetto/schema';

@@ -3,0 +4,0 @@ import { ModelType } from '../types/model';

@@ -47,3 +47,3 @@ import { Class, AppError } from '@travetto/base';

errors: errors.map(x => {
const { message, type, errors: subErrors, details } = x.error;
const { message, type, details: { errors: subErrors } = {}, details } = x.error;
return { message, type, errors: subErrors ?? details, idx: x.idx };

@@ -50,0 +50,0 @@ })

@@ -38,6 +38,3 @@ import { Readable } from 'node:stream';

export interface PartialStream {
stream: Readable;
range: [number, number];
}
export type StreamRange = { start: number, end?: number };

@@ -63,11 +60,5 @@ /**

*/
getStream(location: string): Promise<Readable>;
getStream(location: string, range?: StreamRange): Promise<Readable>;
/**
* Get partial stream from asset store given a starting byte and an optional ending byte
* @param location The location of the stream
*/
getStreamPartial(location: string, start: number, end?: number): Promise<PartialStream>;
/**
* Get metadata for stream

@@ -74,0 +65,0 @@ * @param location The location of the stream

@@ -26,7 +26,7 @@ import assert from 'node:assert';

async wait(n: number | TimeSpan) {
await timers.setTimeout(TimeUtil.timeToMs(n) * this.delayFactor);
await timers.setTimeout(TimeUtil.asMillis(n) * this.delayFactor);
}
timeFromNow(v: number | TimeSpan, unit?: TimeUnit) {
return new Date(Date.now() + TimeUtil.timeToMs(v, unit) * this.delayFactor);
return TimeUtil.fromNow(TimeUtil.asMillis(v, unit) * this.delayFactor);
}

@@ -33,0 +33,0 @@

@@ -152,5 +152,5 @@ import assert from 'node:assert';

await service.create(User4, User4.from({ child: { name: 'bob', age: 40 }, createdDate: TimeUtil.timeFromNow('3d'), color: 'blue' }));
await service.create(User4, User4.from({ child: { name: 'bob', age: 30 }, createdDate: TimeUtil.timeFromNow('2d'), color: 'red' }));
await service.create(User4, User4.from({ child: { name: 'bob', age: 50 }, createdDate: TimeUtil.timeFromNow('-1d'), color: 'green' }));
await service.create(User4, User4.from({ child: { name: 'bob', age: 40 }, createdDate: TimeUtil.fromNow('3d'), color: 'blue' }));
await service.create(User4, User4.from({ child: { name: 'bob', age: 30 }, createdDate: TimeUtil.fromNow('2d'), color: 'red' }));
await service.create(User4, User4.from({ child: { name: 'bob', age: 50 }, createdDate: TimeUtil.fromNow('-1d'), color: 'green' }));

@@ -157,0 +157,0 @@ const arr = await this.toArray(service.listByIndex(User4, 'nameCreated', { child: { name: 'bob' } }));

@@ -6,8 +6,9 @@ import fs from 'node:fs/promises';

import { pipeline } from 'node:stream/promises';
import { buffer as toBuffer } from 'node:stream/consumers';
import { Suite, Test, TestFixtures } from '@travetto/test';
import { StreamUtil } from '@travetto/base';
import { BaseModelSuite } from './base';
import { ModelStreamSupport } from '../../src/service/stream';
import { enforceRange } from '../../src/internal/service/stream';

@@ -80,30 +81,32 @@ @Suite()

const retrieved = await service.getStream(meta.hash);
const content = (await StreamUtil.toBuffer(retrieved)).toString('utf8');
const content = (await toBuffer(retrieved)).toString('utf8');
assert(content.startsWith('abc'));
assert(content.endsWith('xyz'));
const partial = await service.getStreamPartial(meta.hash, 10, 20);
const subContent = (await StreamUtil.toBuffer(partial.stream)).toString('utf8');
assert(subContent.length === (partial.range[1] - partial.range[0]) + 1);
const partial = await service.getStream(meta.hash, { start: 10, end: 20 });
const subContent = (await toBuffer(partial)).toString('utf8');
const range = await enforceRange({ start: 10, end: 20 }, meta.size);
assert(subContent.length === (range.end - range.start) + 1);
assert(subContent === 'klmnopqrstu');
const partialUnbounded = await service.getStreamPartial(meta.hash, 10);
const subContent2 = (await StreamUtil.toBuffer(partialUnbounded.stream)).toString('utf8');
assert(subContent2.length === (partialUnbounded.range[1] - partialUnbounded.range[0]) + 1);
const partialUnbounded = await service.getStream(meta.hash, { start: 10 });
const subContent2 = (await toBuffer(partialUnbounded)).toString('utf8');
const range2 = await enforceRange({ start: 10 }, meta.size);
assert(subContent2.length === (range2.end - range2.start) + 1);
assert(subContent2.startsWith('klm'));
assert(subContent2.endsWith('xyz'));
const partialSingle = await service.getStreamPartial(meta.hash, 10, 10);
const subContent3 = (await StreamUtil.toBuffer(partialSingle.stream)).toString('utf8');
const partialSingle = await service.getStream(meta.hash, { start: 10, end: 10 });
const subContent3 = (await toBuffer(partialSingle)).toString('utf8');
assert(subContent3.length === 1);
assert(subContent3 === 'k');
const partialOverbounded = await service.getStreamPartial(meta.hash, 20, 40);
const subContent4 = (await StreamUtil.toBuffer(partialOverbounded.stream)).toString('utf8');
const partialOverbounded = await service.getStream(meta.hash, { start: 20, end: 40 });
const subContent4 = (await toBuffer(partialOverbounded)).toString('utf8');
assert(subContent4.length === 6);
assert(subContent4.endsWith('xyz'));
await assert.rejects(() => service.getStreamPartial(meta.hash, -10, 10));
await assert.rejects(() => service.getStreamPartial(meta.hash, 30, 37));
await assert.rejects(() => service.getStream(meta.hash, { start: -10, end: 10 }));
await assert.rejects(() => service.getStream(meta.hash, { start: 30, end: 37 }));
}
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc