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

rest-easy-loki

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rest-easy-loki - npm Package Compare versions

Comparing version 0.6.0 to 0.7.0

.prettierrc

7

dist/api.d.ts

@@ -0,3 +1,8 @@

/// <reference types="node" />
import * as http from 'http';
import Koa from 'koa';
import { ICommandOptions } from './models/command-options';
export declare const createApi: (config: Partial<ICommandOptions>) => Koa<Koa.DefaultState, Koa.DefaultContext>;
export declare const createApi: (config: ICommandOptions) => {
api: Koa<Koa.DefaultState, Koa.DefaultContext>;
server?: http.Server | undefined;
};
"use strict";
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -8,8 +15,12 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

const cors = require('@koa/cors');
const fs = __importStar(require("fs"));
const koa_1 = __importDefault(require("koa"));
const koa_body_1 = __importDefault(require("koa-body"));
const koa_static_1 = __importDefault(require("koa-static"));
const path = __importStar(require("path"));
const authorization_1 = require("./authorization");
const logging_1 = require("./logging");
const routes_1 = require("./routes");
const socket_service_1 = require("./socket-service");
const upload_service_1 = require("./upload-service");
const state = {

@@ -29,14 +40,42 @@ pretty: false,

const api = new koa_1.default();
// custom 404
// api.use(async (ctx, next) => {
// await next();
// if (ctx.body || !ctx.idempotent) {
// return;
// }
// ctx.redirect('/404.html');
// });
if (config.cors) {
console.log('Enabling CORS.');
// api.use(cors({ credentials: true }));
api.use(cors());
}
api.use(koa_body_1.default({ formLimit: config.sizeLimit, jsonLimit: config.sizeLimit }));
const ss = config.io ? socket_service_1.createSocketService(api) : undefined;
api.use(koa_body_1.default({
formLimit: config.sizeLimit,
jsonLimit: config.sizeLimit,
multipart: true,
}));
api.use(logging_1.logger);
api.use(koa_static_1.default('./public'));
// Serve public folder
if (config.public) {
api.use(koa_static_1.default(path.resolve(process.cwd(), config.public)));
}
api.use(authorization_1.pep);
api.use(routes_1.router.routes());
api.use(routes_1.router.allowedMethods());
return api;
// Allow uploading files to 'config.upload' folder. Files can be uploaded to /upload/:CONTEXT.
if (config.upload) {
const uploadPath = path.resolve(process.cwd(), config.upload);
if (!fs.existsSync(uploadPath)) {
fs.mkdirSync(uploadPath);
}
api.use(koa_static_1.default(uploadPath));
api.use(upload_service_1.uploadService(uploadPath));
console.log(`Uploading files enabled: POST to /upload/:CONTEXT and the files will be saved in ${uploadPath}.`);
}
const router = routes_1.createRouter(ss ? ss.io : undefined);
api.use(router.routes());
api.use(router.allowedMethods());
return { api, server: ss ? ss.server : undefined };
};
//# sourceMappingURL=api.js.map

@@ -7,4 +7,4 @@ "use strict";

const command_line_args_1 = __importDefault(require("command-line-args"));
const config_1 = require("./config");
const serve_1 = require("./serve");
const config_1 = require("./config");
// tslint:disable-next-line: no-var-requires

@@ -22,3 +22,3 @@ const npm = require('../package.json');

typeLabel: 'Boolean',
description: 'Show the help manual',
description: 'Show the help manual.',
},

@@ -31,5 +31,13 @@ {

defaultValue: config_1.config.cors,
description: 'Enable CORS (default true)',
description: `Enable CORS ($LOKI_CORS ${config_1.config.cors}).`,
},
{
name: 'io',
alias: 'i',
type: Boolean,
typeLabel: 'Boolean',
defaultValue: config_1.config.io,
description: `Enable socket.io ($LOKI_IO ${config_1.config.io}).`,
},
{
name: 'pretty',

@@ -40,3 +48,3 @@ alias: 'v',

typeLabel: 'Boolean',
description: 'Enable pretty output, default taken from environment settings, $LOKI_PRETTY, default true.',
description: `Enable pretty output ($LOKI_PRETTY ${config_1.config.pretty}).`,
},

@@ -49,3 +57,3 @@ {

typeLabel: 'Boolean',
description: 'Port to use, default taken from environment settings, $LOKI_PORT, otherwise 3000',
description: `Port to use ($LOKI_PORT ${config_1.config.port}).`,
},

@@ -58,5 +66,20 @@ {

typeLabel: 'String',
description: 'Message size limit for body parser, $LOKI_SIZE_LIMIT, default 25mb',
description: `Message size limit for body parser ($LOKI_SIZE_LIMIT ${config_1.config.sizeLimit}).`,
},
{
name: 'upload',
alias: 'u',
type: String,
typeLabel: 'String',
description: 'Optional relative path to the `upload` folder to upload files to `/upload/:CONTEXT` URL.',
},
{
name: 'public',
alias: 'b',
defaultValue: 'public',
type: String,
typeLabel: 'String',
description: 'Relative path to a `public` folder to share your files, default \'public\'.',
},
{
name: 'db',

@@ -67,3 +90,3 @@ alias: 'd',

typeLabel: 'String',
description: 'Name of the database taken from environment settings, $LOKI_DB, otherwise `rest_easy_loki.db`.',
description: `Name of the database taken from environment settings ($LOKI_DB ${config_1.config.db}).`,
},

@@ -91,2 +114,10 @@ ];

},
{
desc: '03. Start the service on port 3456, allowing uploading files to the upload folder.',
example: `$ ${cmdName} -p 3456 -u ./upload`,
},
{
desc: '04. Start the service and allow clients to subscribe to updates via socket.io.',
example: `$ ${cmdName} -i`,
},
],

@@ -93,0 +124,0 @@ },

3

dist/config.js

@@ -12,3 +12,4 @@ "use strict";

port: process.env.LOKI_PORT || 3000,
cors: process.env.LOKI_CORS || true,
cors: process.env.LOKI_CORS ? process.env.LOKI_CORS : true,
io: process.env.LOKI_IO ? process.env.LOKI_IO : true,
db: process.env.LOKI_DB || 'rest_easy_loki.db',

@@ -15,0 +16,0 @@ sizeLimit: process.env.LOKI_SIZE_LIMIT || '25mb',

export interface ICommandOptions {
/** Show the manual */
help: boolean;
help?: boolean;
/** Show verbose output */
pretty: boolean;
pretty?: boolean;
/** Port to use */
port: number;
port?: number;
/** Enable CORS */
cors: boolean;
cors?: boolean;
/** Enable Socket.io */
io?: boolean;
/** Static public folder name, default 'public' */
public?: string;
/** Allow file uploads to upload folder, default not activated */
upload?: string;
/** Database name */
db: string;
db?: string;
/** Message size limit for URL-encoded or JSON messages. Used in bodyparser, e.g. 1mb. Default 25mb */
sizeLimit: string;
sizeLimit?: string;
}
import Router from 'koa-router';
export declare const router: Router<any, {}>;
import IO from 'socket.io';
export declare const createRouter: (io?: IO.Server | undefined) => Router<any, {}>;

@@ -11,88 +11,101 @@ "use strict";

const utils_1 = require("./utils");
exports.router = new koa_router_1.default();
exports.router.get('/api/env', async (ctx) => {
ctx.body = environment_1.environment();
});
exports.router.get('/api/collections', async (ctx) => {
ctx.status = 201;
ctx.body = database_1.collections();
});
/**
* Request the whole collection but only returns a subset of all properties
* - Specify `props` containing a comma separted array of top-level properties.
* - Optionally, specify `from` and `to` as query params for pagination, e.g. ?from=0&to=5
*/
exports.router.get('/api/:collection/view', async (ctx) => {
const { collection } = ctx.params;
const map = utils_1.propertyMap(ctx.query);
const filter = utils_1.paginationFilter(ctx.query);
const results = database_1.all(collection, ctx.query.q);
ctx.body =
map && results
? filter
? results.filter(filter).map(map)
: results.map(map)
: results;
});
/** Get by ID */
exports.router.get('/api/:collection/:id', async (ctx) => {
const { collection, id } = ctx.params;
ctx.body = database_1.get(collection, +id);
});
/**
* Request the whole collection
* - Optionally, specify from and to as query params for pagination, e.g. ?from=0&to=5
*/
exports.router.get('/api/:collection', async (ctx) => {
const { collection } = ctx.params;
const pages = utils_1.paginationFilter(ctx.query);
const results = database_1.all(collection, ctx.query.q);
ctx.body = pages && results ? results.filter(pages) : results;
});
exports.router.post('/api/:collection', async (ctx) => {
const { collection } = ctx.params;
const item = ctx.request.body;
ctx.body = database_1.post(collection, item);
});
exports.router.put('/api/:collection/:id', async (ctx) => {
const { collection, id } = ctx.params;
const item = ctx.request.body;
ctx.body = database_1.update(collection, +id, item);
});
exports.router.patch('/api/:collection/:id', async (ctx) => {
const { collection, id } = ctx.params;
if (id) {
const item = database_1.get(collection, +id);
const mutation = ctx.request.body;
if (item && mutation && mutation.patch) {
const { saveChanges, patch } = mutation;
const errors = rfc6902_1.applyPatch(item, patch);
const hasErrors = errors.some(e => e !== null);
if (hasErrors) {
errors.forEach(e => e && console.error(e));
ctx.status = 409;
ctx.body = errors;
}
else {
if (saveChanges) {
delete mutation.saveChanges;
database_1.post(saveChanges, mutation);
exports.createRouter = (io) => {
const router = new koa_router_1.default();
router.get('/api/env', async (ctx) => {
ctx.body = environment_1.environment();
});
router.get('/api/collections', async (ctx) => {
ctx.status = 201;
ctx.body = database_1.collections();
});
/**
* Request the whole collection but only returns a subset of all properties
* - Specify `props` containing a comma separted array of top-level properties.
* - Optionally, specify `from` and `to` as query params for pagination, e.g. ?from=0&to=5
*/
router.get('/api/:collection/view', async (ctx) => {
const { collection } = ctx.params;
const map = utils_1.propertyMap(ctx.query);
const filter = utils_1.paginationFilter(ctx.query);
const results = database_1.all(collection, ctx.query.q);
ctx.body = map && results ? (filter ? results.filter(filter).map(map) : results.map(map)) : results;
});
/** Get by ID */
router.get('/api/:collection/:id', async (ctx) => {
const { collection, id } = ctx.params;
ctx.body = database_1.get(collection, +id);
});
/**
* Request the whole collection
* - Optionally, specify from and to as query params for pagination, e.g. ?from=0&to=5
*/
router.get('/api/:collection', async (ctx) => {
const { collection } = ctx.params;
const pages = utils_1.paginationFilter(ctx.query);
const results = database_1.all(collection, ctx.query.q);
ctx.body = pages && results ? results.filter(pages) : results;
});
router.post('/api/:collection', async (ctx) => {
const { collection } = ctx.params;
const item = ctx.request.body;
ctx.body = database_1.post(collection, item);
if (io) {
io.emit(collection, ctx.body);
}
});
router.put('/api/:collection/:id', async (ctx) => {
const { collection, id } = ctx.params;
const item = ctx.request.body;
ctx.body = database_1.update(collection, +id, item);
if (io) {
io.emit(`${collection}/${id}`, ctx.body);
}
});
router.patch('/api/:collection/:id', async (ctx) => {
const { collection, id } = ctx.params;
if (id) {
const item = database_1.get(collection, +id);
const mutation = ctx.request.body;
if (item && mutation && mutation.patch) {
const { saveChanges, patch } = mutation;
const errors = rfc6902_1.applyPatch(item, patch);
const hasErrors = errors.some(e => e !== null);
if (hasErrors) {
errors.forEach(e => e && console.error(e));
ctx.status = 409;
ctx.body = errors;
}
ctx.body = database_1.update(collection, +id, item);
else {
if (saveChanges) {
delete mutation.saveChanges;
database_1.post(saveChanges, mutation);
}
ctx.body = database_1.update(collection, +id, item);
if (io) {
io.emit(`${collection}/${id}`, ctx.body);
}
}
}
}
}
});
exports.router.put('/api/:collection', async (ctx) => {
const { collection } = ctx.params;
const item = ctx.request.body;
ctx.body = database_1.updateItem(collection, item);
});
exports.router.delete('/api/:collection/:id', async (ctx) => {
const { collection, id } = ctx.params;
ctx.body = database_1.del(collection, +id);
});
// export const routes: compose.Middleware<
// Application.ParameterizedContext<any, Router.IRouterParamContext<any, {}>>
// > = router.routes();
});
router.put('/api/:collection', async (ctx) => {
const { collection } = ctx.params;
const item = ctx.request.body;
ctx.body = database_1.updateItem(collection, item);
if (io && item.id) {
io.emit(`${collection}/${item.id}`, ctx.body);
}
});
router.delete('/api/:collection/:id', async (ctx) => {
const { collection, id } = ctx.params;
ctx.body = database_1.del(collection, +id);
if (io) {
io.emit(`${collection}/${id}`);
}
});
// export const routes: compose.Middleware<
// Application.ParameterizedContext<any, Router.IRouterParamContext<any, {}>>
// > = router.routes();
return router;
};
//# sourceMappingURL=routes.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// import http from 'http';
// import IO from 'socket.io';
const config_1 = require("./config");

@@ -7,4 +9,4 @@ const index_1 = require("./index");

index_1.db.startDatabase(configuration.db, () => {
const api = index_1.createApi(configuration);
api.listen(configuration.port);
const { api, server } = index_1.createApi(configuration);
(server || api).listen(configuration.port);
console.log(`Server running on port ${configuration.port}.`);

@@ -11,0 +13,0 @@ });

{
"name": "rest-easy-loki",
"version": "0.6.0",
"version": "0.7.0",
"description": "A REST interface for lokijs supporting CRUD operations and automatic creation of new collections.",

@@ -15,3 +15,3 @@ "main": "./dist/index.js",

"watch": "tsc -w",
"start": "tsc-watch --onSuccess \"node ./dist/cli.js\" --onFailure \"echo Beep! Compilation Failed\" --compiler typescript/bin/tsc",
"start": "tsc-watch --onSuccess \"node ./dist/cli.js --upload upload\" --onFailure \"echo Beep! Compilation Failed\" --compiler typescript/bin/tsc",
"dry-run": "npm publish --dry-run",

@@ -47,16 +47,18 @@ "patch-release": "npm run clean && npm run build && npm version patch --force -m \"Patch release\" && npm publish && git push --follow-tags",

"lokijs": "^1.5.8",
"rfc6902": "^3.0.4"
"rfc6902": "^3.0.4",
"socket.io": "^2.3.0"
},
"devDependencies": {
"@types/command-line-args": "^5.0.0",
"@types/koa": "^2.0.52",
"@types/koa": "^2.11.0",
"@types/koa-compose": "^3.2.5",
"@types/koa-router": "^7.0.42",
"@types/koa-router": "^7.4.0",
"@types/koa-static": "^4.0.1",
"@types/lokijs": "^1.5.2",
"@types/node": "^12.12.11",
"@types/lokijs": "^1.5.3",
"@types/node": "^13.1.8",
"@types/socket.io": "^2.1.4",
"rimraf": "^3.0.0",
"tsc-watch": "^4.0.0",
"typescript": "^3.7.2"
"tsc-watch": "^4.1.0",
"typescript": "^3.7.5"
}
}

@@ -83,7 +83,15 @@ # REST-EASY-LOKI

- You can use the `public` folder for sharing static files or your own web application.
You can use the `public` folder for sharing static files or your own web application.
### Uploading files
You can use the `upload` folder for uploading files to a (automatically created) CONTEXT folder, if enabled on start-up using the `-u` instruction. Test it via `curl -F "file=@filename.jpg" http://localhost:3030/upload/:CONTEXT`. Files will be served `http://localhost:3030/`.
### Socket.io support
If enabled using the `io` flag (or -i) so clients can subscribe to receive updates when a value has changed. Clients can either subscribe to a collection `socket.subscribe('COLLECTION_NAME')`, or to a collection item `socket.subscribe('COLLECTION_NAME/$LOKI')`. The latter is, for example, useful when you have multiple editors. Subscribers receive the updated item.
### Serving environment variables
- The [http://localhost:3000/api/env](http://localhost:3000/api/env) serves all environment variables that start with `LOKI_` (except the `LOKI_AUTHZ_`, so you don't accidentally share secrets). Since all key-value pairs are strings, a type conversion to boolean, number and arrays (using the , as separator) is performed.
The [http://localhost:3000/api/env](http://localhost:3000/api/env) serves all environment variables that start with `LOKI_` (except the `LOKI_AUTHZ_`, so you don't accidentally share secrets). Since all key-value pairs are strings, a type conversion to boolean, number and arrays (using the , as separator) is performed.

@@ -90,0 +98,0 @@ ### Authorization

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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