Socket
Socket
Sign inDemoInstall

skapi-js

Package Overview
Dependencies
0
Maintainers
1
Versions
447
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.5 to 1.0.6-4.beta-0

js/Main.js.map

15

dist/skapi.js.LICENSE.txt

@@ -21,2 +21,17 @@ /*!

/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */

@@ -21,2 +21,17 @@ /*!

/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */

1

js/Main.js
import Skapi from "./main/skapi";
import SkapiError from "./main/error";
export { Skapi, SkapiError };
//# sourceMappingURL=Main.js.map

42

js/main/error.js
export default class SkapiError extends Error {
constructor(error, options) {
if (Array.isArray(error) && error.length <= 2) {
super(error[1] || 'Something went wrong.');
this.name = options && options.name || "SKAPI";
this.code = error[0] || "ERROR";
if (options) {
if (options.code) {
this.code = options.code;
let msg = error[1];
if (error.length > 2) {
for (let i = 2; i < error.length; i++) {
if (typeof error[i] === 'string') {
msg += error[i];
}
else {
break;
}
}
if (options.cause) {
this.cause = options.cause;
}
}
super((msg || 'Something went wrong.').trim());
this.name = options?.name || "SKAPI";
this.code = options?.code || error[0] || "ERROR";
if (options?.cause) {
this.cause = options.cause;
}
}
else if (typeof error === 'string') {
super(error || 'Something went wrong.');
this.name = "SKAPI";
this.code = 'ERROR';
if (options) {
if (options.code) {
this.code = options.code;
}
if (options.cause) {
this.cause = options.cause;
}
super((error || 'Something went wrong.').trim());
this.name = options?.name || "SKAPI";
this.code = options?.code || 'ERROR';
if (options?.cause) {
this.cause = options.cause;
}
}
else if (error instanceof Error) {
super(error.message || 'Something went wrong.');
super((error.message || 'Something went wrong.').trim());
this.cause = error;

@@ -39,1 +40,2 @@ this.name = error.name;

}
//# sourceMappingURL=error.js.map

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

import { DatabaseResponse, Connection, ProgressCallback, GetRecordQuery, FetchOptions, RecordData, Condition, UserAttributes, UserProfile, Newsletters, FormSubmitCallback, Form, PostRecordConfig, PublicUser } from '../Types';
import { DatabaseResponse, Connection, ProgressCallback, GetRecordQuery, FetchOptions, RecordData, Condition, UserAttributes, UserProfile, Newsletters, Form, PostRecordConfig, PublicUser } from '../Types';
import { extractFormData, fromBase62, generateRandom, toBase62 } from '../utils/utils';
export default class Skapi {

@@ -29,13 +30,74 @@ version: string;

};
util: {
generateRandom: typeof generateRandom;
toBase62: typeof toBase62;
fromBase62: typeof fromBase62;
extractFormData: typeof extractFormData;
request: (url: any, data: any, option: any) => Promise<any>;
};
private __connection;
private __authConnection;
private __socket;
private __socket_group;
constructor(service: string, owner: string, options?: {
autoLogin: boolean;
});
}, __etc?: any);
updateConnection(): Promise<Connection>;
private checkAdmin;
private request;
private getSubscribedTo;
private getSubscribers;
normalizeRecord: any;
private registerTicket;
private unregisterTicket;
connectRealtime(cb: (rt: {
status: 'message' | 'error' | 'success' | 'close' | 'notice';
message: any;
sender?: string;
}) => Promise<WebSocket>): Promise<WebSocket>;
jwtLogin(params: {
idToken: string;
keyUrl: string;
clientId: string;
provider: string;
nonce?: string;
}): Promise<UserProfile>;
clientSecretRequest(params: {
url: string;
clientSecretName: string;
method: 'GET' | 'POST';
headers?: Record<string, string>;
data?: Record<string, string>;
params?: Record<string, string>;
}): Promise<any>;
consumeTicket(params: {
ticket_id: string;
} & {
[key: string]: any;
}): Promise<any>;
getConsumedTickets(params: {
ticket_id?: string;
}, fetchOptions: FetchOptions): Promise<DatabaseResponse<any[]>>;
getTickets(params: {
ticket_id?: string;
}, fetchOptions: FetchOptions): Promise<DatabaseResponse<any[]>>;
closeRealtime(): Promise<void>;
getRealtimeUsers(params: {
group: string;
user_id?: string;
}, fetchOptions?: FetchOptions): Promise<DatabaseResponse<string[]>>;
getRealtimeGroups(params?: {
searchFor: 'group' | 'number_of_users';
value: string | number;
condition?: '>' | '>=' | '=' | '<' | '<=' | '!=' | 'gt' | 'gte' | 'eq' | 'lt' | 'lte' | 'ne';
range?: string | number;
} | null, fetchOptions?: FetchOptions): Promise<DatabaseResponse<{
group: string;
number_of_users: number;
}>>;
postRealtime(message: any, recipient: string): Promise<{
status: 'success';
message: 'Message sent.';
}>;
joinRealtime(params: {
group: string | null;
}): Promise<{
status: 'success';
message: string;
}>;
getConnection(): Promise<Connection>;

@@ -54,3 +116,7 @@ getProfile(options?: {

sync?: boolean;
}>(params: Params | Params[]): Promise<any>;
}, Response = {
response: any;
statusCode: number;
url: string;
}>(params: Params | Params[]): Promise<Response | Response[]>;
getFormResponse(): Promise<any>;

@@ -106,3 +172,3 @@ getRecords(query: GetRecordQuery, fetchOptions?: FetchOptions): Promise<DatabaseResponse<RecordData>>;

getUsers(params?: {
searchFor: 'user_id' | 'email' | 'phone_number' | 'locale' | 'name' | 'address' | 'gender' | 'birthdate';
searchFor: 'user_id' | 'email' | 'phone_number' | 'locale' | 'name' | 'address' | 'gender' | 'birthdate' | 'subscribers' | 'timestamp';
value: string | number | boolean;

@@ -149,3 +215,6 @@ condition?: '>' | '>=' | '=' | '<' | '<=' | '!=' | 'gt' | 'gte' | 'eq' | 'lt' | 'lte' | 'ne';

user_id: string | string[];
}): Promise<string>;
}): Promise<DatabaseResponse<{
record_id: string;
user_id: string;
}>>;
requestPrivateRecordAccessKey(record_id: string): Promise<string>;

@@ -155,5 +224,6 @@ deleteFiles(params: {

}): Promise<RecordData[]>;
uploadFiles(fileList: Form<FileList | File[]>, params: {
uploadFiles(fileList: FormData | HTMLFormElement | SubmitEvent, params: {
record_id: string;
} & FormSubmitCallback): Promise<{
progress?: ProgressCallback;
}): Promise<{
completed: File[];

@@ -167,7 +237,7 @@ failed: File[];

method?: string;
meta?: Record<string, any>;
bypassAwaitConnection?: boolean;
responseType?: string;
responseType?: 'blob' | 'json' | 'text' | 'arrayBuffer' | 'formData' | 'document';
contentType?: string;
} & FormSubmitCallback): Promise<{
progress?: ProgressCallback;
}): Promise<{
mockResponse: Record<string, any>;

@@ -188,14 +258,16 @@ }>;

login?: boolean;
} & FormSubmitCallback): Promise<UserProfile | "SUCCESS: The account has been created. User's signup confirmation is required." | 'SUCCESS: The account has been created.'>;
} & {
progress?: ProgressCallback;
}): Promise<UserProfile | "SUCCESS: The account has been created. User's signup confirmation is required." | 'SUCCESS: The account has been created.'>;
resetPassword(form: Form<{
email: string;
code?: string | number;
new_password?: string;
code: string | number;
new_password: string;
}>): Promise<"SUCCESS: New password has been set.">;
verifyEmail(form?: Form<{
code: string;
}>): Promise<'SUCCESS: Verification code has been sent.' | 'SUCCESS: "email" is verified.'>;
}>): Promise<string>;
verifyPhoneNumber(form?: Form<{
code: string;
}>): Promise<'SUCCESS: Verification code has been sent.' | 'SUCCESS: "phone_number" is verified.'>;
}>): Promise<string>;
forgotPassword(form: Form<{

@@ -209,3 +281,5 @@ email: string;

updateProfile(form: Form<UserAttributes>): Promise<UserProfile>;
postRecord(form: Form<Record<string, any>> | null | undefined, config: PostRecordConfig & FormSubmitCallback): Promise<RecordData>;
postRecord(form: Form<Record<string, any>> | null | undefined, config: PostRecordConfig & {
progress?: ProgressCallback;
}): Promise<RecordData>;
getSubscriptions(params: {

@@ -212,0 +286,0 @@ subscriber?: string;

@@ -9,6 +9,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {

import validator from '../utils/validator';
import { getRecords, postRecord, deleteRecords, getTables, getIndexes, getTags, uploadFiles, getFile, grantPrivateRecordAccess, removePrivateRecordAccess, listPrivateRecordAccess, requestPrivateRecordAccessKey, deleteFiles, normalizeRecord } from '../methods/database';
import { request, secureRequest, mock, getFormResponse, formHandler, getConnection } from '../methods/request';
import { subscribe, unsubscribe, blockSubscriber, unblockSubscriber, getSubscribers, getSubscribedTo, getSubscriptions, subscribeNewsletter, getNewsletters, unsubscribeNewsletter, getNewsletterSubscription } from '../methods/subscription';
import { checkAdmin, getProfile, logout, recoverAccount, resendSignupConfirmation, authentication, login, signup, disableAccount, resetPassword, verifyEmail, verifyPhoneNumber, forgotPassword, changePassword, updateProfile, getUsers, setUserPool, userPool, lastVerifiedEmail, requestUsernameChange } from '../methods/user';
import { getRecords, postRecord, deleteRecords, getTables, getIndexes, getTags, getFile, grantPrivateRecordAccess, removePrivateRecordAccess, listPrivateRecordAccess, requestPrivateRecordAccessKey, deleteFiles } from '../methods/database';
import { connectRealtime, joinRealtime, postRealtime, closeRealtime, getRealtimeUsers, getRealtimeGroups } from '../methods/realtime';
import { secureRequest, mock, clientSecretRequest } from '../methods/request';
import { request, getFormResponse, formHandler, uploadFiles } from '../utils/network';
import { subscribe, unsubscribe, blockSubscriber, unblockSubscriber, getSubscriptions, subscribeNewsletter, getNewsletters, unsubscribeNewsletter, getNewsletterSubscription } from '../methods/subscription';
import { getProfile, logout, recoverAccount, resendSignupConfirmation, authentication, login, signup, disableAccount, resetPassword, verifyEmail, verifyPhoneNumber, forgotPassword, changePassword, updateProfile, getUsers, setUserPool, userPool, lastVerifiedEmail, requestUsernameChange, consumeTicket, getConsumedTickets, getTickets, registerTicket, unregisterTicket, jwtLogin } from '../methods/user';
import { extractFormData, fromBase62, generateRandom, toBase62 } from '../utils/utils';
export default class Skapi {

@@ -25,4 +28,4 @@ get user() {

}
constructor(service, owner, options) {
this.version = '1.0.5';
constructor(service, owner, options, __etc) {
this.version = '1.0.64';
this.session = null;

@@ -87,7 +90,13 @@ this.connection = null;

};
this.checkAdmin = checkAdmin.bind(this);
this.request = request.bind(this);
this.getSubscribedTo = getSubscribedTo.bind(this);
this.getSubscribers = getSubscribers.bind(this);
this.normalizeRecord = normalizeRecord.bind(this);
this.util = {
generateRandom,
toBase62,
fromBase62,
extractFormData,
request: (url, data, option) => {
return request.bind(this)(url, data, option, { ignoreService: true });
}
};
this.registerTicket = registerTicket.bind(this);
this.unregisterTicket = unregisterTicket.bind(this);
if (typeof service !== 'string' || typeof owner !== 'string') {

@@ -104,3 +113,5 @@ throw new SkapiError('"service" and "owner" should be type <string>.', { code: 'INVALID_PARAMETER' });

this.owner = owner;
let autoLogin = typeof options?.autoLogin === 'boolean' ? options.autoLogin : true;
let autoLogin = !!options?.autoLogin;
this.target_cdn = __etc?.target_cdn || this.target_cdn;
this.hostDomain = __etc?.hostDomain || this.hostDomain;
const cdn_domain = `https://${this.target_cdn}.cloudfront.net`;

@@ -157,5 +168,5 @@ let sreg = service.substring(0, 4);

this.__connection = (async () => {
let process = null;
let connection = null;
if (!restore?.connection) {
process = this.updateConnection();
connection = this.updateConnection();
}

@@ -182,10 +193,15 @@ const storeClassProperties = () => {

};
return (process instanceof Promise) ? process.then(() => exec()) : exec();
return (connection instanceof Promise) ? connection.then(() => exec()) : exec();
};
window.addEventListener('beforeunload', storeClassProperties);
window.addEventListener("visibilitychange", storeClassProperties);
await process;
window.addEventListener('beforeunload', () => {
storeClassProperties();
this.closeRealtime();
});
await connection;
await this.__authConnection;
let skapi = `%c\r\n $$\\ $$\\ \r\n $$ | \\__|\r\n $$$$$$$\\ $$ | $$\\ $$$$$$\\ $$$$$$\\ $$\\ \r\n$$ _____|$$ | $$ |\\____$$\\ $$ __$$\\ $$ |\r\n\\$$$$$$\\ $$$$$$ \/ $$$$$$$ |$$ \/ $$ |$$ |\r\n \\____$$\\ $$ _$$< $$ __$$ |$$ | $$ |$$ |\r\n$$$$$$$ |$$ | \\$$\\\\$$$$$$$ |$$$$$$$ |$$ |\r\n\\_______\/ \\__| \\__|\\_______|$$ ____\/ \\__|\r\n $$ | \r\n $$ | \r\n \\__| \r\n`;
console.log(`Built with:\n${skapi}Version: ${this.version}\n\nDocumentation: https://docs.skapi.com`, `font-family: monospace; color:blue;`);
if (this.connection.group === 1) {
console.log(`%cSKAPI: THE SERVICE IS IN TRIAL MODE. ALL THE USERS AND DATA WILL BE INITIALIZED EVERY 7 DAYS.`, `font-family: monospace; color:red;`);
}
return this.connection;

@@ -201,4 +217,37 @@ })();

}
connectRealtime(cb) {
return connectRealtime.bind(this)(cb);
}
jwtLogin(params) {
return jwtLogin.bind(this)(params);
}
clientSecretRequest(params) {
return clientSecretRequest.bind(this)(params);
}
consumeTicket(params) {
return consumeTicket.bind(this)(params);
}
getConsumedTickets(params, fetchOptions) {
return getConsumedTickets.bind(this)(params, fetchOptions);
}
getTickets(params, fetchOptions) {
return getTickets.bind(this)(params, fetchOptions);
}
closeRealtime() {
return closeRealtime.bind(this)();
}
getRealtimeUsers(params, fetchOptions) {
return getRealtimeUsers.bind(this)(params, fetchOptions);
}
getRealtimeGroups(params, fetchOptions) {
return getRealtimeGroups.bind(this)(params, fetchOptions);
}
postRealtime(message, recipient) {
return postRealtime.bind(this)(message, recipient);
}
joinRealtime(params) {
return joinRealtime.bind(this)(params);
}
getConnection() {
return getConnection.bind(this)();
return this.__connection;
}

@@ -303,5 +352,23 @@ getProfile(options) {

formHandler()
], Skapi.prototype, "getConnection", null);
], Skapi.prototype, "consumeTicket", null);
__decorate([
formHandler()
], Skapi.prototype, "getConsumedTickets", null);
__decorate([
formHandler()
], Skapi.prototype, "getTickets", null);
__decorate([
formHandler()
], Skapi.prototype, "getRealtimeUsers", null);
__decorate([
formHandler()
], Skapi.prototype, "getRealtimeGroups", null);
__decorate([
formHandler()
], Skapi.prototype, "postRealtime", null);
__decorate([
formHandler()
], Skapi.prototype, "joinRealtime", null);
__decorate([
formHandler()
], Skapi.prototype, "getProfile", null);

@@ -428,1 +495,2 @@ __decorate([

], Skapi.prototype, "subscribeNewsletter", null);
//# sourceMappingURL=skapi.js.map

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

import { RecordData, Form, FormSubmitCallback, FetchOptions, DatabaseResponse, GetRecordQuery, Condition, PostRecordConfig, ProgressCallback } from '../Types';
import { RecordData, Form, FetchOptions, DatabaseResponse, GetRecordQuery, Condition, PostRecordConfig, ProgressCallback } from '../Types';
export declare function normalizeRecord(record: Record<string, any>): RecordData;

@@ -6,9 +6,2 @@ export declare function deleteFiles(params: {

}): Promise<RecordData[]>;
export declare function uploadFiles(fileList: Form<FileList | File[]>, params: {
record_id: string;
} & FormSubmitCallback): Promise<{
completed: File[];
failed: File[];
bin_endpoints: string[];
}>;
export declare function getFile(url: string, config?: {

@@ -22,3 +15,4 @@ dataType?: 'base64' | 'download' | 'endpoint' | 'blob';

}, fetchOptions?: FetchOptions): Promise<DatabaseResponse<RecordData>>;
export declare function postRecord(form: Form<Record<string, any>> | null | undefined, config: PostRecordConfig & FormSubmitCallback & {
export declare function postRecord(form: Form<Record<string, any>> | null | undefined, config: PostRecordConfig & {
progress?: ProgressCallback;
reference_private_key?: string;

@@ -75,11 +69,14 @@ }): Promise<RecordData>;

user_id: string | string[];
}): any;
}): Promise<any>;
export declare function removePrivateRecordAccess(params: {
record_id: string;
user_id: string | string[];
}): any;
}): Promise<any>;
export declare function listPrivateRecordAccess(params: {
record_id: string;
user_id: string | string[];
}): void;
export declare function requestPrivateRecordAccessKey(record_id: string): any;
}): Promise<DatabaseResponse<{
record_id: string;
user_id: string;
}>>;
export declare function requestPrivateRecordAccessKey(record_id: string): Promise<any>;
import SkapiError from '../main/error';
import { extractFormMeta, generateRandom } from '../utils/utils';
import { extractFormData, fromBase62 } from '../utils/utils';
import validator from '../utils/validator';
import { request } from './request';
import { request, uploadFiles } from '../utils/network';
import { checkAdmin } from './user';
const __index_number_range = 4503599627370496;
function fromBase62(str) {
const base62Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
let result = 0;
for (let i = 0; i < str.length; i++) {
result = result * 62 + base62Chars.indexOf(str[i]);
}
return result;
}
export function normalizeRecord(record) {
function base_decode(chars) {
let charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
return chars.split('').reverse().reduce((prev, curr, i) => prev + (charset.indexOf(curr) * (62 ** i)), 0);
}
const output = {

@@ -52,3 +41,3 @@ user_id: '',

let base62timestamp = r.substring(0, r.length - 9);
let uploaded = base_decode(base62timestamp);
let uploaded = fromBase62(base62timestamp);
output.uploaded = uploaded;

@@ -210,3 +199,3 @@ },

}
let updatedRec = request.bind(this)('del-files', {
let updatedRec = await request.bind(this)('del-files', {
endpoints,

@@ -217,135 +206,2 @@ storage: 'records'

}
export async function uploadFiles(fileList, params) {
await this.__connection;
let params_request = params?.request || 'post';
let nestKey = params?.nestKey || '';
let service = params?.service || this.service;
if (params_request === 'post') {
if (!params?.record_id) {
throw new SkapiError('"record_id" is required.', { code: 'INVALID_PARAMETER' });
}
}
else {
if (service === this.service) {
throw new SkapiError('invalid service.', { code: 'INVALID_PARAMETER' });
}
if (params_request !== 'host') {
throw new SkapiError('invalid request.', { code: 'INVALID_PARAMETER' });
}
}
if (fileList instanceof SubmitEvent) {
fileList = fileList.target;
}
if (fileList instanceof HTMLFormElement) {
fileList = new FormData(fileList);
}
let formDataKeys = [];
if (fileList instanceof FormData) {
let fileEntries = [];
for (let entry of fileList.entries()) {
let value = entry[1];
if (value instanceof File) {
let key = entry[0];
formDataKeys.push(key);
fileEntries.push(value);
}
}
fileList = fileEntries;
}
if (!(fileList[0] instanceof File)) {
throw new SkapiError('"fileList" should be a FileList or array of File object.', { code: 'INVALID_PARAMETER' });
}
let reserved_key = generateRandom();
let getSignedParams = {
reserved_key,
service,
request: params_request
};
if (params?.record_id) {
getSignedParams.id = params.record_id;
}
let xhr;
let fetchProgress = (url, body, progressCallback) => {
return new Promise((res, rej) => {
xhr = new XMLHttpRequest();
xhr.open('POST', url);
xhr.onload = (e) => {
let result = xhr.responseText;
try {
result = JSON.parse(result);
}
catch (err) { }
if (xhr.status >= 200 && xhr.status < 300) {
let result = xhr.responseText;
try {
result = JSON.parse(result);
}
catch (err) { }
res(result);
}
else {
rej(result);
}
};
xhr.onerror = () => rej('Network error');
xhr.onabort = () => rej('Aborted');
xhr.ontimeout = () => rej('Timeout');
if (xhr.upload && typeof params.progress === 'function') {
xhr.upload.onprogress = progressCallback;
}
xhr.send(body);
});
};
let completed = [];
let failed = [];
function toBase62(num) {
const base62Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
if (num === 0)
return base62Chars[0];
let result = '';
while (num > 0) {
result = base62Chars[num % 62] + result;
num = Math.floor(num / 62);
}
return result;
}
let bin_endpoints = [];
for (let i = 0; i < fileList.length; i++) {
let f = fileList[i];
let key = formDataKeys?.[i] || '';
let signedParams = Object.assign({
key: params_request === 'host' ? (nestKey ? nestKey + '/' : '') + f.name : key ? key + '/' + f.name : f.name,
sizeKey: toBase62(f.size),
contentType: f.type || null
}, getSignedParams);
let { fields = null, url, cdn } = await request.bind(this)('get-signed-url', signedParams, { auth: true });
bin_endpoints.push(cdn);
let form = new FormData();
for (let name in fields) {
form.append(name, fields[name]);
}
form.append('file', f);
try {
await fetchProgress(url, form, (p) => {
if (typeof params.progress !== 'function')
return;
params.progress({
status: 'upload',
progress: p.loaded / p.total * 100,
currentFile: f,
completed,
failed,
loaded: p.loaded,
total: p.total,
abort: () => xhr.abort()
});
});
completed.push(f);
}
catch (err) {
failed.push(f);
}
}
return { completed, failed, bin_endpoints };
}
export async function getFile(url, config) {

@@ -380,9 +236,9 @@ if (typeof url !== 'string') {

config = validator.Params(config, {
expires: 'number',
dataType: ['base64', 'blob', 'endpoint', 'download', () => 'download'],
progress: p => p
expires: ['number', () => 0],
dataType: ['base64', 'blob', 'endpoint', () => 'download'],
progress: 'function'
});
let needAuth = target_key[0] == 'auth';
let filename = url.split('/').slice(-1)[0];
let expires = config?.expires || 0;
let expires = config.expires;
if (expires) {

@@ -447,3 +303,3 @@ if (expires < 0) {

try {
let b = await request.bind(this)(url, { service: service || this.service }, { method: 'get', noParams: true, contentType: null, responseType: 'blob', fetchOptions: { progress: config?.progress } });
let b = await request.bind(this)(url, { service: service || this.service }, { method: 'get', contentType: null, responseType: 'blob', fetchOptions: { progress: config?.progress } });
if (config?.dataType === 'base64') {

@@ -463,7 +319,2 @@ const reader = new FileReader();

await this.__connection;
const indexTypes = {
'$updated': 'number',
'$uploaded': 'number',
'$referenced_count': 'number'
};
if (typeof query?.table === 'string') {

@@ -475,144 +326,176 @@ query.table = {

}
const struct = {
table: {
name: 'string',
access_group: ['number', 'private', 'public', 'authorized'],
subscription: (v) => validator.UserId(v, 'User ID in "subscription"')
},
reference: 'string',
index: {
name: (v) => {
if (typeof v !== 'string') {
throw new SkapiError('"index.name" should be type: string.', { code: 'INVALID_PARAMETER' });
let is_reference_fetch = '';
let ref_user = '';
if (query?.record_id) {
validator.specialChars(query.record_id, 'record_id', false, false);
let outputObj = { record_id: query.record_id };
if (query?.service) {
outputObj.service = query.service;
}
query = outputObj;
if (this.__private_access_key[query.record_id]) {
query.private_key = this.__private_access_key[query.record_id];
}
}
else {
const struct = {
table: {
name: [v => {
if (!v) {
throw new SkapiError('"table.name" cannot be empty string.', { code: 'INVALID_PARAMETER' });
}
return validator.specialChars(v, 'table name', true, true);
}, () => { throw new SkapiError('"table.name" is required.', { code: 'INVALID_PARAMETER' }); }],
access_group: [v => {
if (v === undefined) {
if (!this.__user && query.table.hasOwnProperty('subscription')) {
return 1;
}
else {
return 0;
}
}
if (typeof v === 'number') {
if (!this.__user && v > 0) {
throw new SkapiError("User has no access", { code: 'INVALID_REQUEST' });
}
if (this.__user.access_group < v) {
throw new SkapiError("User has no access", { code: 'INVALID_REQUEST' });
}
}
else if (typeof v === 'string') {
v = {
private: 'private',
public: 0,
authorized: 1
}[v];
if (v === 'private' && !this.__user) {
throw new SkapiError('Unsigned users have no access to private records.', { code: 'INVALID_REQUEST' });
}
if (v === undefined) {
throw new SkapiError('"table.access_group" is invalid.', { code: 'INVALID_PARAMETER' });
}
}
else {
throw new SkapiError('"table.access_group" should be type: <number | string>.', { code: 'INVALID_PARAMETER' });
}
return v;
}],
subscription: (v) => {
if (v === null || v === undefined) {
return v;
}
validator.UserId(v, 'User ID in "subscription"');
if (!this.__user) {
throw new SkapiError('Unsigned users have no access to subscription records.', { code: 'INVALID_REQUEST' });
}
return {
user_id: v,
group: 1
};
}
if (indexTypes.hasOwnProperty(v)) {
},
reference: v => {
if (v === null || v === undefined) {
return v;
}
if (['$uploaded', '$updated', '$referenced_count', '$user_id'].includes(v)) {
if (typeof v === 'string') {
try {
ref_user = validator.UserId(v);
}
catch (err) {
validator.specialChars(v, 'reference', false, false);
is_reference_fetch = v;
if (this.__private_access_key[is_reference_fetch]) {
query.private_key = this.__private_access_key[is_reference_fetch];
}
}
is_reference_fetch = v;
return v;
}
return validator.specialChars(v, 'index.name', true, false);
else {
throw new SkapiError('"reference" should be type: string.', { code: 'INVALID_PARAMETER' });
}
},
value: (v) => {
if (query.index?.name && indexTypes.hasOwnProperty(query.index.name)) {
let tp = indexTypes[query.index.name];
if (typeof v === tp) {
index: {
name: ['$updated', '$uploaded', '$referenced_count', '$user_id', (v) => {
if (v === undefined) {
throw new SkapiError('"index.name" is required.', { code: 'INVALID_PARAMETER' });
}
if (typeof v !== 'string') {
throw new SkapiError('"index.name" should be type: string.', { code: 'INVALID_PARAMETER' });
}
return validator.specialChars(v, 'index.name', true, false);
}],
value: (v) => {
const indexTypes = {
'$updated': 'number',
'$uploaded': 'number',
'$referenced_count': 'number',
'$user_id': validator.UserId
};
if (indexTypes.hasOwnProperty(query.index.name)) {
let tp = indexTypes[query.index.name];
if (typeof tp === 'string') {
if (typeof v === tp) {
if (!v) {
return;
}
return validator.specialChars(v, 'index.value', false, true);
}
else {
throw new SkapiError(`"index.value" should be type: ${tp}.`, { code: 'INVALID_PARAMETER' });
}
}
if (typeof tp === 'function') {
return tp(v);
}
}
if (typeof v === 'number') {
if (v > __index_number_range || v < -__index_number_range) {
throw new SkapiError(`Number value should be within range -${__index_number_range} ~ +${__index_number_range}`, { code: 'INVALID_PARAMETER' });
}
return v;
}
else {
throw new SkapiError(`"index.value" should be type: ${tp}.`, { code: 'INVALID_PARAMETER' });
else if (typeof v === 'boolean') {
return v;
}
}
if (typeof v === 'number') {
if (v > __index_number_range || v < -__index_number_range) {
throw new SkapiError(`Number value should be within range -${__index_number_range} ~ +${__index_number_range}`, { code: 'INVALID_PARAMETER' });
},
condition: ['gt', 'gte', 'lt', 'lte', '>', '>=', '<', '<=', '=', 'eq', '!=', 'ne'],
range: (v) => {
if (!query.index || !('value' in query.index)) {
throw new SkapiError('"index.value" is required.', { code: 'INVALID_PARAMETER' });
}
if (query.index.name === '$record_id') {
throw new SkapiError(`Cannot do "index.range" on ${query.index.name}`, { code: 'INVALID_PARAMETER' });
}
if (typeof query.index.value !== typeof v) {
throw new SkapiError('"index.range" type should match the type of "index.value".', { code: 'INVALID_PARAMETER' });
}
if (typeof v === 'string') {
return validator.specialChars(v, 'index.range', false, true);
}
return v;
}
else if (typeof v === 'boolean') {
},
tag: v => {
if (v === null || v === undefined) {
return v;
}
if (typeof v === 'string') {
return validator.specialChars(v, 'tag', false, true);
}
else {
if ('$user_id' == query.index?.name) {
return validator.UserId(v);
}
return validator.specialChars(v, 'index.value', false, true);
throw new SkapiError('"tag" should be type: string.', { code: 'INVALID_PARAMETER' });
}
},
condition: ['gt', 'gte', 'lt', 'lte', '>', '>=', '<', '<=', '=', 'eq', '!=', 'ne'],
range: (v) => {
if (!query.index || !('value' in query.index)) {
throw new SkapiError('"index.value" is required.', { code: 'INVALID_PARAMETER' });
}
if (query.index.name === '$record_id') {
throw new SkapiError(`Cannot do "index.range" on ${query.index.name}`, { code: 'INVALID_PARAMETER' });
}
if (typeof query.index.value !== typeof v) {
throw new SkapiError('"index.range" type should match the type of "index.value".', { code: 'INVALID_PARAMETER' });
}
if (typeof v === 'string') {
return validator.specialChars(v, 'index.range', false, true);
}
return v;
}
},
tag: 'string',
private_key: 'string'
};
if (query?.tag) {
validator.specialChars(query.tag, 'tag', false, true);
private_key: 'string'
};
let isAdmin = await checkAdmin.bind(this)();
query = validator.Params(query || {}, struct, ref_user || isAdmin ? [] : ['table']);
}
if (query?.table) {
if (query.table.access_group === 'public') {
query.table.access_group = 0;
}
else if (query.table.access_group === 'authorized') {
query.table.access_group = 1;
}
if (query.table?.name) {
validator.specialChars(query.table.name, 'table name', true, true);
}
if (typeof query.table.access_group === 'number') {
if (!this.__user) {
if (0 < query.table.access_group) {
throw new SkapiError("User has no access", { code: 'INVALID_REQUEST' });
}
}
else if (this.user.access_group < query.table.access_group) {
throw new SkapiError("User has no access", { code: 'INVALID_REQUEST' });
}
}
}
if (query?.index && !query.index?.name) {
throw new SkapiError('"index.name" is required when using "index" parameter.', { code: 'INVALID_REQUEST' });
}
let is_reference_fetch = '';
if (query?.record_id) {
validator.specialChars(query.record_id, 'record_id', false, false);
let outputObj = { record_id: query.record_id };
if (query?.service) {
outputObj.service = query.service;
}
query = outputObj;
if (this.__private_access_key[query.record_id]) {
query.private_key = this.__private_access_key[query.record_id];
}
}
else {
let ref_user;
if (!this.session && query.table?.access_group === 'private') {
throw new SkapiError('Unsigned users have no access to private records.', { code: 'INVALID_REQUEST' });
}
if (query.reference) {
try {
ref_user = validator.UserId(query.reference);
}
catch (err) {
validator.specialChars(query.reference, 'reference', false, false);
is_reference_fetch = query.reference;
if (this.__private_access_key[is_reference_fetch]) {
query.private_key = this.__private_access_key[is_reference_fetch];
}
}
}
let isAdmin = await this.checkAdmin();
let q = validator.Params(query || {}, struct, ref_user || isAdmin ? [] : ['table']);
if (typeof q.table !== 'string') {
if (q.table?.subscription) {
if (!this.session) {
throw new SkapiError('Unsigned users have no access to subscription records.', { code: 'INVALID_REQUEST' });
}
q.table.subscription = {
user_id: q.table.subscription,
group: 1
};
}
}
query = q;
}
let auth = query.hasOwnProperty('access_group') && typeof query.table !== 'string' && query.table.access_group ? true : !!this.__user;
let result = await request.bind(this)('get-records', query, {
fetchOptions,
auth,
method: auth ? 'post' : 'get'
auth: !!this.__user,
method: !!this.__user ? 'post' : 'get'
});

@@ -629,3 +512,3 @@ for (let i in result.list) {

export async function postRecord(form, config) {
let isAdmin = await this.checkAdmin();
let isAdmin = await checkAdmin.bind(this)();
if (!config) {

@@ -637,7 +520,2 @@ throw new SkapiError('"config" argument is required.', { code: 'INVALID_PARAMETER' });

}
let fetchOptions = {};
if (typeof config?.formData === 'function') {
fetchOptions.formData = config.formData;
delete config.formData;
}
if (typeof config.table === 'string') {

@@ -656,17 +534,53 @@ config.table = {

}
let progress = config.progress || null;
let reference_private_key = null;
let config_chkd = validator.Params(config || {}, {
record_id: 'string',
let _config = validator.Params(config || {}, {
record_id: ['string', () => {
if (!config.table || !config.table.name) {
throw new SkapiError('"table.name" is required.', { code: 'INVALID_PARAMETER' });
}
}],
readonly: 'boolean',
table: {
name: 'string',
subscription: 'boolean',
access_group: ['number', 'private', 'public', 'authorized']
name: v => {
if (!v) {
throw new SkapiError('"table.name" cannot be empty string.', { code: 'INVALID_PARAMETER' });
}
return validator.specialChars(v, 'table name', true, true);
},
subscription: v => {
if (v) {
if (!config.record_id && !config.table.access_group || config.table.access_group === 0 || config.table.access_group === 'public') {
throw new SkapiError('Public records cannot require subscription.', { code: 'INVALID_REQUEST' });
}
}
return v;
},
access_group: v => {
if (typeof v === 'string') {
v = {
private: 'private',
public: 0,
authorized: 1
}[v];
}
if (typeof v === 'number') {
if (!isAdmin && this.user.access_group < v) {
throw new SkapiError("User has no access", { code: 'INVALID_REQUEST' });
}
}
if (v === undefined) {
throw new SkapiError('"table.access_group" is invalid.', { code: 'INVALID_PARAMETER' });
}
if (isAdmin && !config.record_id) {
if (v === 'private') {
throw new SkapiError('Service owner cannot write private records.', { code: 'INVALID_REQUEST' });
}
}
return v;
}
},
reference: {
record_id: (v) => {
record_id: v => {
validator.specialChars(v, '"reference.record_id"', false, false);
if (this.__private_access_key[v]) {
reference_private_key = this.__private_access_key[v];
config.reference_private_key = this.__private_access_key[v];
}

@@ -693,22 +607,37 @@ return v;

index: {
name: 'string',
value: ['string', 'number', 'boolean']
name: ['$uploaded', '$updated', '$referenced_count', '$user_id', v => {
if (!v) {
throw new SkapiError('"index.name" is required.', { code: 'INVALID_PARAMETER' });
}
if (typeof v === 'string') {
validator.specialChars(v, 'index name', true);
return v;
}
throw new SkapiError('"index.name" should be type: string.', { code: 'INVALID_PARAMETER' });
}],
value: [v => {
if (!v) {
throw new SkapiError('"index.value" is required.', { code: 'INVALID_PARAMETER' });
}
if (typeof v === 'string') {
validator.specialChars(v, 'index value', false, true);
}
else if (typeof v === 'number') {
if (v > __index_number_range || v < -__index_number_range) {
throw new SkapiError(`Number value should be within range -${__index_number_range} ~ +${__index_number_range}`, { code: 'INVALID_PARAMETER' });
}
}
return v;
}]
},
tags: (v) => {
if (v === null) {
if (v === null || v === undefined) {
return v;
}
console.log({ v });
if (typeof v === 'string') {
return [v];
v = v.split(',').map(t => t.trim());
}
if (Array.isArray(v)) {
for (let i of v) {
if (typeof i !== 'string') {
throw new SkapiError(`"tags" should be type: <string | string[]>`, { code: 'INVALID_PARAMETER' });
}
validator.specialChars(v, 'tag', false, true);
}
return v;
}
throw new SkapiError(`"tags" should be type: <string | string[]>`, { code: 'INVALID_PARAMETER' });
console.log({ v });
return validator.specialChars(v, 'tag', false, true);
},

@@ -729,91 +658,33 @@ remove_bin: (v) => {

else {
throw new SkapiError(`"remove_bin" should be type: <string | BinaryFile[]>`, { code: 'INVALID_PARAMETER' });
throw new SkapiError(`"remove_bin" should be type: <string[] | BinaryFile[]>`, { code: 'INVALID_PARAMETER' });
}
}
}
else {
throw new SkapiError(`"remove_bin" should be type: <string[] | BinaryFile[]>`, { code: 'INVALID_PARAMETER' });
}
return arr;
}
}, [], ['response', 'onerror', 'progress'], null);
if (!config_chkd?.table && !config_chkd?.record_id) {
throw new SkapiError('Either "record_id" or "table" should have a value.', { code: 'INVALID_PARAMETER' });
},
progress: 'function',
});
let progress = config.progress || null;
if (config.table.hasOwnProperty('subscription')) {
_config.table.subscription_group = config.table.subscription ? 1 : null;
delete _config.table.subscription;
}
if (typeof config_chkd.table !== 'string' && config_chkd.table) {
if (config_chkd.table.access_group === 'public') {
config_chkd.table.access_group = 0;
}
else if (config_chkd.table.access_group === 'authorized') {
config_chkd.table.access_group = 1;
}
if (typeof config_chkd.table.access_group === 'number') {
if (!isAdmin && this.user.access_group < config_chkd.table.access_group) {
throw new SkapiError("User has no access", { code: 'INVALID_REQUEST' });
}
}
if (!config_chkd.table.name) {
throw new SkapiError('"table.name" cannot be empty string.', { code: 'INVALID_PARAMETER' });
}
validator.specialChars(config_chkd.table.name, 'table name', true, true);
if (isAdmin) {
if (config_chkd.table.access_group === 'private') {
throw new SkapiError('Service owner cannot write private records.', { code: 'INVALID_REQUEST' });
}
}
if (config_chkd.table?.subscription) {
config_chkd.table.subscription_group = 1;
delete config_chkd.table.subscription;
}
}
config = config_chkd;
delete config.response;
delete config.onerror;
delete config.progress;
if (reference_private_key) {
config.reference_private_key = reference_private_key;
}
if (config.index) {
if (!config.index.name || typeof config.index.name !== 'string') {
throw new SkapiError('"index.name" is required. type: string.', { code: 'INVALID_PARAMETER' });
}
if (!['$uploaded', '$updated', '$referenced_count', '$user_id'].includes(config.index.name)) {
validator.specialChars(config.index.name, 'index name', true);
}
if (!config.index.hasOwnProperty('value')) {
throw new SkapiError('"index.value" is required.', { code: 'INVALID_PARAMETER' });
}
if (typeof config.index.value === 'string') {
validator.specialChars(config.index.value, 'index value', false, true);
}
else if (typeof config.index.value === 'number') {
if (config.index.value > __index_number_range || config.index.value < -__index_number_range) {
throw new SkapiError(`Number value should be within range -${__index_number_range} ~ +${__index_number_range}`, { code: 'INVALID_PARAMETER' });
}
}
}
delete _config.progress;
let options = { auth: true };
let postData = null;
let to_bin = null;
if ((form instanceof HTMLFormElement) || (form instanceof FormData) || (form instanceof SubmitEvent)) {
form = (form instanceof SubmitEvent) ? form.target : form;
let formMeta = extractFormMeta(form);
if (formMeta.to_bin.length) {
to_bin = formMeta.to_bin;
let extractedForm = extractFormData(form);
if (extractedForm) {
if (extractedForm.files.length) {
to_bin = extractedForm.files;
}
if (formMeta.files.length) {
let formData = new FormData();
for (let f of formMeta.files) {
formData.append(f.name, f.file, f.file.name);
}
options.meta = config;
if (Object.keys(formMeta.meta).length) {
options.meta.data = formMeta.meta;
}
postData = formData;
}
else {
postData = Object.assign({ data: formMeta.meta }, config);
}
postData = Object.assign({ data: extractedForm.data }, _config);
}
else {
postData = Object.assign({ data: form }, config);
postData = Object.assign({ data: form }, _config);
}
let fetchOptions = {};
if (typeof progress === 'function') {

@@ -835,4 +706,4 @@ fetchOptions.progress = progress;

};
if (config.hasOwnProperty('service')) {
uploadFileParams['service'] = config.service;
if (_config.hasOwnProperty('service')) {
uploadFileParams['service'] = _config.service;
}

@@ -955,3 +826,3 @@ let { bin_endpoints } = await uploadFiles.bind(this)(bin_formData, uploadFileParams);

export async function deleteRecords(params) {
let isAdmin = await this.checkAdmin();
let isAdmin = await checkAdmin.bind(this)();
if (isAdmin && !params?.service) {

@@ -979,5 +850,2 @@ throw new SkapiError('Service ID is required.', { code: 'INVALID_PARAMETER' });

if (!params?.table) {
if (isAdmin) {
return null;
}
throw new SkapiError('Either "table" or "record_id" is required.', { code: 'INVALID_PARAMETER' });

@@ -1004,26 +872,27 @@ }

subscription: (v) => {
if (isAdmin && typeof params?.table?.subscription === 'string') {
return validator.UserId(v, 'User ID in "table.subscription"');
}
if (typeof v === 'boolean') {
if (v) {
return this.__user.user_id;
v = this.__user.user_id;
return v;
}
else {
return null;
}
}
if (!params.table.hasOwnProperty('access_group')) {
throw new SkapiError('"table.access_group" is required for subscription records.', { code: 'INVALID_PARAMETER' });
}
else if (params.table.access_group === 0) {
throw new SkapiError('Public tables does not hold subscription records.', { code: 'INVALID_REQUEST' });
}
if (isAdmin && typeof v === 'string') {
return validator.UserId(v, 'User ID in "table.subscription"');
}
throw new SkapiError('"table.subscription" is an invalid parameter key.', { code: 'INVALID_PARAMETER' });
},
}
};
let table_p = validator.Params(params.table || {}, struct, isAdmin ? [] : ['name']);
if (table_p.subscription === null) {
delete table_p.subscription;
let table = validator.Params(params.table || {}, struct, isAdmin ? [] : ['name']);
if (table.subscription) {
table.subscription_group = 1;
}
else {
table_p.subscription_group = 1;
}
params.table = table_p;
let toDelete = Object.assign({}, params, { table });
return await request.bind(this)('del-records', toDelete, { auth: true });
}
return await request.bind(this)('del-records', params, { auth: true });
}

@@ -1056,4 +925,4 @@ export function grantPrivateRecordAccess(params) {

}
export function listPrivateRecordAccess(params) {
let list = recordAccess.bind(this)({
export async function listPrivateRecordAccess(params) {
let list = await recordAccess.bind(this)({
record_id: params.record_id,

@@ -1068,2 +937,3 @@ user_id: params.user_id || null,

});
return list;
}

@@ -1107,1 +977,2 @@ export function requestPrivateRecordAccessKey(record_id) {

}
//# sourceMappingURL=database.js.map

@@ -1,12 +0,9 @@

import { Form, FormSubmitCallback, FetchOptions, Connection } from '../Types';
export declare function getConnection(): Promise<Connection>;
export declare function request(url: string, data?: Form<any> | null, options?: {
noParams?: boolean;
fetchOptions?: FetchOptions & FormSubmitCallback;
auth?: boolean;
method?: string;
meta?: Record<string, any>;
bypassAwaitConnection?: boolean;
responseType?: string;
contentType?: string;
import { Form, ProgressCallback } from '../Types';
export declare function clientSecretRequest(params: {
url: string;
clientSecretName: string;
method: 'GET' | 'POST';
headers?: Record<string, string>;
data?: Record<string, string>;
params?: Record<string, string>;
}): Promise<any>;

@@ -17,4 +14,8 @@ export declare function secureRequest<RequestParams = {

sync?: boolean;
}>(params: RequestParams | RequestParams[]): Promise<any>;
export declare function mock(data: Form<any | {
}, Response = {
response: any;
statusCode: number;
url: string;
}>(params: RequestParams | RequestParams[]): Promise<Response | Response[]>;
export declare function mock(data: Form<any & {
raise?: 'ERR_INVALID_REQUEST' | 'ERR_INVALID_PARAMETER' | 'SOMETHING_WENT_WRONG' | 'ERR_EXISTS' | 'ERR_NOT_EXISTS';

@@ -24,12 +25,8 @@ }>, options?: {

method?: string;
meta?: Record<string, any>;
responseType?: 'blob' | 'json' | 'text' | 'arrayBuffer' | 'formData' | 'document';
contentType?: string;
progress?: ProgressCallback;
bypassAwaitConnection?: boolean;
responseType?: string;
contentType?: string;
} & FormSubmitCallback): Promise<{
}): Promise<{
mockResponse: Record<string, any>;
}>;
export declare function getFormResponse(): Promise<any>;
export declare function formHandler(options?: {
preventMultipleCalls: boolean;
}): (target: object, propertyKey: string, descriptor: any) => void;
import SkapiError from '../main/error';
import { MD5, generateRandom } from '../utils/utils';
import validator from '../utils/validator';
const __pendingRequest = {};
export function getConnection() {
return this.__connection;
}
export async function request(url, data = null, options) {
options = options || {};
let { auth = false, method = 'post', meta = null, bypassAwaitConnection = false, } = options;
method = method.toLowerCase();
let __connection = bypassAwaitConnection ? null : (await this.__connection);
if (!__connection && !bypassAwaitConnection) {
throw new SkapiError('Invalid connection. The service could have been disabled, or has a restricted CORS.', { code: 'INVALID_REQUEST' });
}
let token = auth ? this.session?.idToken?.jwtToken : null;
if (auth) {
if (!token) {
this.logout();
throw new SkapiError('User login is required.', { code: 'INVALID_REQUEST' });
}
else {
let currTime = Date.now() / 1000;
if (this.session.idToken.payload.exp < currTime) {
try {
await this.authentication().getSession({ refreshToken: true });
token = this.session?.idToken?.jwtToken;
}
catch (err) {
this.logout();
throw new SkapiError('User login is required.', { code: 'INVALID_REQUEST' });
}
import { request } from '../utils/network';
export function clientSecretRequest(params) {
let hasSecret = false;
let checkClientSecretPlaceholder = (v) => {
for (let k in v) {
if (typeof v[k] === 'string' && v[k].includes('$CLIENT_SECRET')) {
hasSecret = true;
break;
}
}
}
let isExternalUrl = '';
try {
isExternalUrl = validator.Url(url);
}
catch (err) {
}
const getEndpoint = async (dest, auth) => {
const endpoints = await Promise.all([
this.admin_endpoint,
this.record_endpoint
]);
const admin = endpoints[0];
const record = endpoints[1];
const get_ep = () => {
switch (dest) {
case 'get-newsletters':
case 'get-public-newsletters':
case 'delete-newsletter':
case 'block-account':
case 'register-service':
case 'get-users':
case 'post-userdata':
case 'remove-account':
case 'post-secure':
case 'subscribe-newsletter':
case 'subscribe-public-newsletter':
case 'signup':
case 'confirm-signup':
case 'recover-account':
case 'mock':
case 'get-services':
case 'service':
case 'grant-access':
case 'last-verified-email':
case 'get-newsletter-subscription':
case 'request-username-change':
case 'register-subdomain':
case 'list-host-directory':
case 'refresh-cdn':
case 'request-newsletter-sender':
case 'set-404':
case 'subdomain-info':
return {
public: admin.admin_public,
private: admin.admin_private
};
case 'post-record':
case 'get-records':
case 'subscription':
case 'get-subscription':
case 'del-records':
case 'get-table':
case 'get-tag':
case 'get-index':
case 'storage-info':
case 'get-signed-url':
case 'grant-private-access':
case 'request-private-access-key':
case 'del-files':
return {
private: record.record_private,
public: record.record_public
};
default:
return null;
}
};
return (get_ep()?.[auth ? 'private' : 'public'] || '') + dest;
};
let endpoint = isExternalUrl || (await getEndpoint(url, !!auth));
let service = this.session?.attributes?.['custom:service'] || __connection?.service || this.service;
let owner = this.session?.attributes?.['custom:owner'] || __connection?.owner || this.owner;
if (meta) {
if (typeof meta === 'object' && !Array.isArray(meta)) {
meta = JSON.parse(JSON.stringify(meta));
}
else {
throw new SkapiError('Invalid meta data.', { code: 'INVALID_REQUEST' });
}
}
if (Array.isArray(data) || data && typeof data !== 'object') {
throw new SkapiError('Request data should be a JSON Object | FormData | HTMLFormElement.', { code: 'INVALID_REQUEST' });
}
let required = options?.responseType !== 'blob' ? { service, owner } : {};
let fetchOptions = {};
let { fetchMore = false, progress } = options?.fetchOptions || {};
if (options?.fetchOptions && Object.keys(options.fetchOptions).length) {
let fetOpt = {};
for (let k of ['limit', 'startKey', 'ascending']) {
if (options.fetchOptions.hasOwnProperty(k)) {
fetOpt[k] = options.fetchOptions[k];
validator.Params(params, {
url: 'string',
clientSecretName: 'string',
method: (v) => {
if (v && typeof v !== 'string') {
throw new SkapiError('"method" should be type: <string>.', { code: 'INVALID_PARAMETER' });
}
}
fetOpt = validator.Params(fetOpt, {
limit: 'number',
startKey: null,
ascending: 'boolean'
});
if (fetOpt.hasOwnProperty('limit') && typeof fetOpt.limit === 'number') {
if (fetOpt.limit > 1000) {
throw new SkapiError('Fetch limit should be below 1000.', { code: 'INVALID_REQUEST' });
if (v.toLowerCase() !== 'get' && v.toLowerCase() !== 'post') {
throw new SkapiError('"method" should be either "GET" or "POST".', { code: 'INVALID_PARAMETER' });
}
Object.assign(fetchOptions, { limit: fetOpt.limit });
}
if (fetOpt.hasOwnProperty('startKey') && typeof fetOpt.startKey === 'object' && fetOpt.startKey && Object.keys(fetOpt.startKey)) {
Object.assign(fetchOptions, { startKey: fetOpt.startKey });
}
if (fetOpt.hasOwnProperty('ascending') && typeof fetOpt.ascending === 'boolean') {
Object.assign(fetchOptions, { ascending: fetOpt.ascending });
}
}
Object.assign(required, fetchOptions);
let isForm = false;
if (data instanceof SubmitEvent) {
data = data?.target;
}
if (data instanceof HTMLFormElement) {
data = new FormData(data);
}
if (data instanceof FormData) {
isForm = true;
}
if (meta) {
meta = Object.assign(required, meta);
}
else {
if (!data) {
data = required;
}
else if (isForm) {
for (let k in required) {
if (required[k] !== undefined) {
data.set(k, new Blob([JSON.stringify(required[k])], {
type: 'application/json'
}));
}
return v.toLowerCase();
},
headers: (v) => {
if (v && typeof v !== 'object') {
throw new SkapiError('"headers" should be type: <object>.', { code: 'INVALID_PARAMETER' });
}
}
else {
data = Object.assign(required, data);
}
}
if (isForm && typeof options?.fetchOptions?.formData === 'function') {
let cb = options.fetchOptions.formData(data);
if (cb instanceof Promise) {
cb = await cb;
}
if (cb instanceof FormData) {
data = cb;
}
if (data instanceof FormData) {
let totalFileSize = 0;
for (let pair of data.entries()) {
let v = pair[1];
if (v instanceof File) {
totalFileSize += v.size;
}
else if (v instanceof FileList) {
if (v && v.length > 0) {
for (let idx = 0; idx <= v.length - 1; idx++) {
totalFileSize += v.item(idx).size;
}
}
}
checkClientSecretPlaceholder(v);
return v;
},
data: (v) => {
if (v && typeof v !== 'object') {
throw new SkapiError('"data" should be type: <object>.', { code: 'INVALID_PARAMETER' });
}
if (totalFileSize > 4200000) {
throw new SkapiError('Files cannot exceed 4MB. Use skapi.uploadFiles(...) instead.', { code: 'INVALID_REQUEST' });
checkClientSecretPlaceholder(v);
return v;
},
params: (v) => {
if (v && typeof v !== 'object') {
throw new SkapiError('"params" should be type: <object>.', { code: 'INVALID_PARAMETER' });
}
checkClientSecretPlaceholder(v);
return v;
}
else {
throw new SkapiError('Callback for extractFormData() should return FormData', { code: 'INVALID_PARAMETER' });
}
}, ['clientSecretName', 'method', 'url']);
if (!hasSecret) {
throw new SkapiError(`At least one parameter value should include "$CLIENT_SECRET" in ${params.method.toLowerCase() === 'post' ? '"data"' : '"params"'} or "headers".`, { code: 'INVALID_PARAMETER' });
}
let requestKey = load_startKey_keys.bind(this)({
params: data,
url: isExternalUrl || url,
fetchMore: isForm ? false : fetchMore
});
if (requestKey && typeof requestKey === 'object') {
return requestKey;
}
if (!requestKey || typeof requestKey !== 'string') {
return null;
}
if (!(__pendingRequest[requestKey] instanceof Promise)) {
let headers = {
'Accept': '*/*'
};
if (token) {
headers.Authorization = token;
}
if (meta) {
let meta_key = '__meta__' + generateRandom(16);
if (data instanceof FormData) {
headers["Content-Meta"] = window.btoa(encodeURIComponent(JSON.stringify({
meta_key: meta_key,
merge: 'data'
})));
data.set(meta_key, new Blob([JSON.stringify(meta)], {
type: 'application/json'
}));
}
}
if (options.hasOwnProperty('contentType')) {
if (options?.contentType) {
headers["Content-Type"] = options.contentType;
}
}
else if (!(data instanceof FormData)) {
headers["Content-Type"] = 'application/json';
}
let opt = { headers };
if (options?.responseType) {
opt.responseType = options.responseType;
}
if (method === 'post') {
__pendingRequest[requestKey] = _post.bind(this)(endpoint, data, opt, progress);
}
else if (method === 'get') {
__pendingRequest[requestKey] = _get.bind(this)(endpoint, data, opt, progress, options?.noParams);
}
try {
let response = await __pendingRequest[requestKey];
if (isForm) {
return response;
}
else {
return update_startKey_keys.bind(this)({
hashedParam: requestKey,
url,
response
});
}
}
catch (err) {
throw err;
}
finally {
if (requestKey && __pendingRequest.hasOwnProperty(requestKey)) {
delete __pendingRequest[requestKey];
}
}
}
return request.bind(this)("client-secret-request", params);
}
;
function load_startKey_keys(option) {
let { params = {}, url, fetchMore = false } = option || {};
if (params.hasOwnProperty('startKey') && params.startKey) {
if (typeof params.startKey !== 'object' && !Object.keys(params.startKey).length &&
params.startKey !== 'start' && params.startKey !== 'end') {
throw new SkapiError(`"${params.startKey}" is invalid startKey key.`, { code: 'INVALID_PARAMETER' });
}
switch (params.startKey) {
case 'start':
fetchMore = false;
delete params.startKey;
}
}
let hashedParams = (() => {
if (params && typeof params === 'object' && Object.keys(params).length) {
function orderObjectKeys(obj) {
function sortObject(obj) {
if (typeof obj === 'object' && obj) {
return Object.keys(obj).sort().reduce((res, key) => (res[key] = obj[key], res), {});
}
return obj;
}
;
let _obj = sortObject(obj);
if (_obj.hasOwnProperty('limit')) {
delete _obj.limit;
}
for (let k in _obj) {
if (_obj[k] && typeof _obj[k] === 'object') {
_obj[k] = sortObject(obj[k]);
}
}
return _obj;
}
return MD5.hash(url + '/' + JSON.stringify(orderObjectKeys(params)));
}
return MD5.hash(url + '/' + this.service);
})();
if (!fetchMore && this.__startKeyHistory?.[url]?.[hashedParams]) {
if (this.__cached_requests?.[url] && this.__cached_requests?.[url]?.[hashedParams]) {
delete this.__cached_requests[url][hashedParams];
}
if (Array.isArray(this.__startKeyHistory[url][hashedParams]) && this.__startKeyHistory[url][hashedParams].length) {
for (let p of this.__startKeyHistory[url][hashedParams]) {
let hashedParams_cached = hashedParams + '/' + MD5.hash(JSON.stringify(p));
if (this.__cached_requests?.[url] && this.__cached_requests?.[url]?.[hashedParams_cached]) {
delete this.__cached_requests[url][hashedParams_cached];
}
}
}
delete this.__startKeyHistory[url][hashedParams];
return hashedParams;
}
if (!Array.isArray(this.__startKeyHistory?.[url]?.[hashedParams])) {
return hashedParams;
}
let list_of_startKeys = this.__startKeyHistory[url][hashedParams];
let last_startKey_key = list_of_startKeys[list_of_startKeys.length - 1];
let cache_hashedParams = hashedParams;
if (last_startKey_key) {
if (last_startKey_key === 'end') {
return {
list: [],
startKey: 'end',
endOfList: true,
startKeyHistory: this.__startKeyHistory[url][hashedParams]
};
}
else {
cache_hashedParams += MD5.hash(last_startKey_key);
params.startKey = JSON.parse(last_startKey_key);
}
}
if (this.__cached_requests?.[url]?.[cache_hashedParams]) {
return this.__cached_requests[url][cache_hashedParams];
}
return hashedParams;
}
;
async function update_startKey_keys(option) {
let { hashedParam, url, response } = option;
let fetched = null;
if (response instanceof Promise) {
fetched = await response;
}
else {
fetched = response;
}
if (!fetched ||
typeof fetched !== 'object' ||
!fetched.hasOwnProperty('startKey') ||
!hashedParam ||
!url) {
return fetched;
}
if (!this.__startKeyHistory.hasOwnProperty(url)) {
this.__startKeyHistory[url] = {};
}
if (!this.__cached_requests?.[url]) {
this.__cached_requests[url] = {};
}
this.__cached_requests[url][hashedParam] = fetched;
if (!this.__startKeyHistory[url].hasOwnProperty(hashedParam)) {
this.__startKeyHistory[url][hashedParam] = [];
}
let startKey_string = fetched.startKey === 'end' ? 'end' : JSON.stringify(fetched.startKey);
if (!this.__startKeyHistory[url][hashedParam].includes(startKey_string)) {
this.__startKeyHistory[url][hashedParam].push(startKey_string);
}
this.__cached_requests[url][hashedParam] = fetched;
return Object.assign({ startKeyHistory: this.__startKeyHistory[url][hashedParam] }, fetched);
}
;
async function _fetch(url, opt, progress) {
let fetchProgress = (url, opts, progress) => {
return new Promise((res, rej) => {
let xhr = new XMLHttpRequest();
xhr.open((opt.method || 'GET').toUpperCase(), url);
for (var k in opts.headers || {}) {
xhr.setRequestHeader(k, opts.headers[k]);
}
if (opt.responseType) {
xhr.responseType = opt.responseType;
}
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
if (opts.responseType == 'json' || opts.responseType == 'blob') {
res(xhr.response);
}
else {
let result = xhr.responseText;
try {
result = JSON.parse(result);
}
catch (err) { }
res(result);
}
}
else {
let status = xhr.status;
let errCode = [
'INVALID_CORS',
'INVALID_REQUEST',
'SERVICE_DISABLED',
'INVALID_PARAMETER',
'ERROR',
'EXISTS',
'NOT_EXISTS'
];
let result = xhr.responseText;
try {
result = JSON.parse(result);
}
catch (err) { }
if (typeof result === 'string') {
let errMsg = xhr.response.split(':');
let code = errMsg.splice(0, 1)[0].trim();
rej(new SkapiError(errMsg.join('').trim(), { code: (errCode.includes(code) ? code : 'ERROR') }));
}
else if (typeof result === 'object' && result?.message) {
let code = (result?.code || (status ? status.toString() : null) || 'ERROR');
rej(new SkapiError(result?.message, { code: code }));
}
}
};
xhr.onerror = () => rej('Network error');
xhr.onabort = () => rej('Aborted');
xhr.ontimeout = () => rej('Timeout');
if (typeof progress === 'function') {
xhr.onprogress = (p) => {
progress({
status: 'download',
progress: p.loaded / p.total * 100,
loaded: p.loaded,
total: p.total,
abort: () => xhr.abort()
});
};
if (xhr.upload) {
xhr.upload.onprogress = (p) => {
progress({
status: 'upload',
progress: p.loaded / p.total * 100,
loaded: p.loaded,
total: p.total,
abort: () => xhr.abort()
});
};
}
}
xhr.send(opts.body);
});
};
let received = await fetchProgress(url, {
headers: opt?.headers,
body: opt.body,
responseType: opt?.responseType
}, progress);
if (typeof received === 'object' && opt.method === 'GET' && received.hasOwnProperty('body')) {
try {
received = JSON.parse(received.body);
}
catch (err) { }
}
return received;
}
;
async function _post(url, params, option, progress) {
let opt = Object.assign({
method: 'POST'
}, option, {
body: params instanceof FormData ? params : JSON.stringify(params)
});
return _fetch.bind(this)(url, opt, progress);
}
;
async function _get(url, params, option, progress, noParams) {
if (params && typeof params === 'object' && !noParams && Object.keys(params).length) {
if (url.substring(url.length - 1) !== '?') {
url = url + '?';
}
let query = Object.keys(params)
.map(k => {
let value = params[k];
if (typeof value !== 'string') {
value = JSON.stringify(value);
}
return encodeURIComponent(k) + '=' + encodeURIComponent(value);
})
.join('&');
url += query;
}
let opt = Object.assign({
method: 'GET'
}, option);
return _fetch.bind(this)(url, opt, progress);
}
;
export async function secureRequest(params) {
await this.__connection;
let paramsStruct = {

@@ -524,3 +59,3 @@ url: (v) => {

},
data: null,
data: v => v,
sync: ['boolean', () => true]

@@ -536,133 +71,14 @@ };

}
return await request.bind(this)('post-secure', params, { auth: true });
return request.bind(this)('post-secure', params, { auth: true });
}
;
export async function mock(data, options) {
let { auth = true, method = 'POST', meta, bypassAwaitConnection = false, responseType, contentType } = options || {};
let { response, onerror, formData, progress } = options || {};
if (options) {
Object.assign({ auth, method, meta, bypassAwaitConnection, responseType, contentType }, {
fetchOptions: { response, onerror, formData, progress }
});
}
await this.__connection;
let { auth = true, method = 'POST', bypassAwaitConnection = false, responseType, contentType, progress } = options || {};
options = Object.assign({ auth, method, bypassAwaitConnection, responseType, contentType }, {
fetchOptions: { progress }
});
return request.bind(this)('mock', data, options);
}
;
export async function getFormResponse() {
await this.__connection;
let responseKey = `${this.service}:${MD5.hash(window.location.href.split('?')[0])}`;
let stored = window.sessionStorage.getItem(responseKey);
if (stored !== null) {
try {
stored = JSON.parse(stored);
}
catch (err) { }
return stored;
}
throw new SkapiError("Form response doesn't exist.", { code: 'NOT_EXISTS' });
}
;
const pendPromise = {};
export function formHandler(options) {
let { preventMultipleCalls = false } = options || {};
return function (target, propertyKey, descriptor) {
const fn = descriptor.value;
descriptor.value = function (...arg) {
let form = arg[0];
let option = arg?.[1] || {};
let routeWithDataKey = true;
let formEl = null;
let actionDestination = '';
if (form instanceof SubmitEvent) {
form.preventDefault();
let currentUrl = window.location.href;
formEl = form.target;
let href = new URL(formEl.action);
actionDestination = href.href;
if (!formEl.action || href.href === currentUrl) {
routeWithDataKey = false;
}
}
const handleResponse = (response) => {
if (option?.response) {
if (typeof option.response === 'function') {
return option.response(response);
}
else {
throw new SkapiError('Callback "response" should be type: function.', { code: 'INVALID_PARAMETER' });
}
}
if (formEl) {
if (routeWithDataKey) {
window.sessionStorage.setItem(`${this.service}:${MD5.hash(actionDestination)}`, JSON.stringify(response));
window.location.href = actionDestination;
}
}
return response;
};
let response;
let handleError = (err) => {
if (form instanceof SubmitEvent) {
form.preventDefault();
}
if (err instanceof SkapiError) {
err.name = propertyKey + '()';
}
else {
err = err instanceof Error ? err : new SkapiError(err, { name: propertyKey + '()' });
}
if (option?.onerror) {
if (typeof option.onerror === 'function') {
return option.onerror(err);
}
else {
return new SkapiError('Callback "onerror" should be type: function.', { code: 'INVALID_PARAMETER', name: propertyKey + '()' });
}
}
return err;
};
const executeMethod = () => {
try {
response = fn.bind(this)(...arg);
}
catch (err) {
let is_err = handleError(err);
if (is_err instanceof Error) {
throw is_err;
}
return is_err;
}
if (response instanceof Promise) {
return (async () => {
try {
let resolved = await response;
return handleResponse(resolved);
}
catch (err) {
let is_err = handleError(err);
if (is_err instanceof Error) {
throw is_err;
}
return is_err;
}
})();
}
};
if (preventMultipleCalls) {
return (async () => {
if (pendPromise?.[propertyKey] instanceof Promise) {
return pendPromise[propertyKey];
}
else {
pendPromise[propertyKey] = executeMethod().finally(() => {
pendPromise[propertyKey] = null;
});
return pendPromise[propertyKey];
}
})();
}
return executeMethod();
};
};
}
;
//# sourceMappingURL=request.js.map

@@ -17,8 +17,2 @@ import { DatabaseResponse, FetchOptions, Form, Newsletters, SubscriptionGroup } from '../Types';

export declare function unblockSubscriber(option: SubscriptionGroup<number | '*'>): Promise<'SUCCESS: unblocked user id "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx".'>;
export declare function getSubscribedTo(option: SubscriptionGroup<number | undefined> & {
blocked?: boolean;
}, fetchOptions: FetchOptions): Promise<DatabaseResponse<any>>;
export declare function getSubscribers(option: SubscriptionGroup<number | undefined> & {
blocked?: boolean;
}, fetchOptions: FetchOptions): Promise<DatabaseResponse<any>>;
export declare function getNewsletterSubscription(params: {

@@ -43,5 +37,5 @@ group?: number | 'public' | 'authorized';

value: string | number;
range: string | number;
group: 'public' | 'authorized' | number;
range?: string | number;
condition?: '>' | '>=' | '=' | '<' | '<=' | 'gt' | 'gte' | 'eq' | 'lt' | 'lte';
group: 'public' | 'authorized' | number;
}, fetchOptions?: FetchOptions): Promise<Newsletters>;
import SkapiError from '../main/error';
import validator from '../utils/validator';
import { request } from './request';
function subscriptionGroupCheck(option) {
option = validator.Params(option, {
user_id: (v) => validator.UserId(v, '"user_id"'),
import { request } from '../utils/network';
import { checkAdmin } from './user';
function subscriptionIdCheck(option) {
return validator.Params(option, {
user_id: (v) => {
if (!this.__user) {
throw new SkapiError('User should be logged in.', { code: 'INVALID_REQUEST' });
}
if (v === this.__user.user_id) {
throw new SkapiError(`"user_id" cannot be the user's own ID.`, { code: 'INVALID_PARAMETER' });
}
return validator.UserId(v, '"user_id"');
},
}, ['user_id']);
if (this.__user && option.user_id === this.__user.user_id) {
throw new SkapiError(`"user_id" cannot be the user's own ID.`, { code: 'INVALID_PARAMETER' });
}
return option;
}

@@ -39,3 +44,3 @@ ;

await this.__connection;
let { user_id } = subscriptionGroupCheck.bind(this)(option);
let { user_id } = subscriptionIdCheck.bind(this)(option);
return await request.bind(this)('subscription', {

@@ -48,3 +53,3 @@ subscribe: user_id,

await this.__connection;
let { user_id } = subscriptionGroupCheck.bind(this)(option);
let { user_id } = subscriptionIdCheck.bind(this)(option);
return await request.bind(this)('subscription', {

@@ -57,3 +62,3 @@ unsubscribe: user_id,

await this.__connection;
let { user_id } = subscriptionGroupCheck.bind(this)(option);
let { user_id } = subscriptionIdCheck.bind(this)(option);
return await request.bind(this)('subscription', { block: user_id, group: 1 }, { auth: true });

@@ -63,35 +68,8 @@ }

await this.__connection;
let { user_id } = subscriptionGroupCheck.bind(this)(option);
let { user_id } = subscriptionIdCheck.bind(this)(option);
return await request.bind(this)('subscription', { unblock: user_id, group: 1 }, { auth: true });
}
export async function getSubscribedTo(option, fetchOptions) {
await this.__connection;
option = validator.Params(option, {
user_id: (v) => validator.UserId(v, '"user_id"'),
blocked: 'boolean'
}) || {};
return getSubscriptions.bind(this)({
subscriber: option.user_id || this.__user?.user_id,
group: 1,
blocked: option.blocked
}, fetchOptions);
}
;
export async function getSubscribers(option, fetchOptions) {
await this.__connection;
option = validator.Params(option, {
user_id: (v) => validator.UserId(v, '"user_id"'),
blocked: 'boolean'
}) || {};
let subParams = {
subscription: option.user_id || this.__user?.user_id,
group: 1,
blocked: option.blocked
};
return getSubscriptions.bind(this)(subParams, fetchOptions);
}
;
export async function getNewsletterSubscription(params) {
await this.__connection;
let isAdmin = await this.checkAdmin();
let isAdmin = await checkAdmin.bind(this)();
params = validator.Params(params, {

@@ -156,3 +134,3 @@ user_id: v => {

export async function getNewsletters(params, fetchOptions) {
let isAdmin = await this.checkAdmin();
let isAdmin = await checkAdmin.bind(this)();
let searchType = {

@@ -166,17 +144,15 @@ 'message_id': 'string',

if (!params) {
if (!fetchOptions) {
fetchOptions = {};
}
fetchOptions.ascending = false;
fetchOptions = Object.assign({ ascending: false }, (fetchOptions || {}));
}
let _params = params || {
params = params || {
searchFor: 'timestamp',
value: 0,
condition: '>'
value: Date.now(),
condition: '<',
group: 'public'
};
params = validator.Params(_params, {
params = validator.Params(params, {
searchFor: ['message_id', 'timestamp', 'read', 'complaint', 'group', 'subject'],
value: (v) => {
if (typeof v !== searchType[_params.searchFor]) {
throw new SkapiError(`"value" type does not match the type of "${_params.searchFor}" index.`, { code: 'INVALID_PARAMETER' });
if (typeof v !== searchType[params.searchFor]) {
throw new SkapiError(`"value" type does not match the type of "${params.searchFor}" index.`, { code: 'INVALID_PARAMETER' });
}

@@ -189,3 +165,3 @@ else if (typeof v === 'string' && !v) {

range: (v) => {
if (!_params.hasOwnProperty('value') || typeof v !== typeof _params.value) {
if (!params.hasOwnProperty('value') || typeof v !== typeof params.value) {
throw new SkapiError('"range" should match type of "value".', { code: 'INVALID_PARAMETER' });

@@ -197,17 +173,18 @@ }

group: (x) => {
if (x === 'public') {
return 0;
}
if (!this.session) {
throw new SkapiError('User should be logged in.', { code: 'INVALID_REQUEST' });
}
if (x === 'public') {
return 0;
}
else if (x === 'authorized') {
if (x === 'authorized') {
return 1;
}
else if (typeof x === 'number') {
if (typeof x === 'number') {
if (!isAdmin && x > parseInt(this.session.idToken.payload.access_group)) {
throw new SkapiError('User has no access.', { code: 'INVALID_REQUEST' });
}
return x;
}
return x;
throw new SkapiError('"group" should be type: number | "public" | "authorized".', { code: 'INVALID_PARAMETER' });
}

@@ -243,1 +220,2 @@ }, ['searchFor', 'value', 'group']);

}
//# sourceMappingURL=subscription.js.map
import { CognitoUser, CognitoUserSession, CognitoUserPool } from 'amazon-cognito-identity-js';
import { Form, FormSubmitCallback, UserProfile, FetchOptions, DatabaseResponse, UserAttributes, PublicUser } from '../Types';
import { Form, UserProfile, FetchOptions, DatabaseResponse, UserAttributes, PublicUser, ProgressCallback } from '../Types';
export declare let userPool: CognitoUserPool | null;

@@ -8,2 +8,89 @@ export declare function setUserPool(params: {

}): void;
export declare function consumeTicket(params: {
ticket_id: string;
} & {
[key: string]: any;
}): Promise<any>;
export declare function getTickets(params: {
ticket_id?: string;
}, fetchOptions?: FetchOptions): Promise<DatabaseResponse<any[]>>;
export declare function getConsumedTickets(params: {
ticket_id?: string;
}, fetchOptions?: FetchOptions): Promise<DatabaseResponse<any[]>>;
export declare function registerTicket(params: {
ticket_id: string;
condition?: {
bypassConditionMismatch?: boolean;
method?: 'GET' | 'POST';
headers?: {
key: string;
value: string | string[];
operator: 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'ne' | '>' | '>=' | '<' | '<=' | '=' | '!=';
}[];
ip?: {
value: string | string[];
operator: 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'ne' | '>' | '>=' | '<' | '<=' | '=' | '!=';
};
user_agent?: {
value: string | string[];
operator: 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'ne' | '>' | '>=' | '<' | '<=' | '=' | '!=';
};
data?: {
key?: string;
value: any | any[];
operator: 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'ne' | '>' | '>=' | '<' | '<=' | '=' | '!=';
setValueWhenMatch?: any | any[];
ignoreMismatch?: boolean;
}[];
params?: {
key?: string;
value: string | string[];
operator: 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'ne' | '>' | '>=' | '<' | '<=' | '=' | '!=';
setValueWhenMatch?: any | any[];
ignoreMismatch?: boolean;
}[];
user?: {
key: string;
value: string | string[];
operator: 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'ne' | '>' | '>=' | '<' | '<=' | '=' | '!=';
}[];
record_access?: string;
request?: {
url: string;
method: 'GET' | 'POST';
headers?: {
[key: string]: string;
};
data?: Record<string, any>;
params?: Record<string, any>;
match: {
key: string;
operator: 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'ne' | '>' | '>=' | '<' | '<=' | '=' | '!=';
value: any | any[];
}[];
};
};
action?: {
access_group: number;
record_access?: string;
request?: {
url: string;
method: 'GET' | 'POST';
headers?: {
[key: string]: string;
};
data?: Record<string, any>;
params?: Record<string, any>;
};
};
description: string;
count?: number;
time_to_live?: number;
placeholder?: {
[key: string]: string;
};
}): Promise<string>;
export declare function unregisterTicket(params: {
ticket_id: string;
}): Promise<string>;
export declare function authentication(): {

@@ -27,2 +114,9 @@ getSession: (option?: {

export declare function recoverAccount(redirect?: boolean | string): Promise<"SUCCESS: Recovery e-mail has been sent.">;
export declare function jwtLogin(params: {
idToken: string;
keyUrl: string;
clientId: string;
provider: string;
nonce?: string;
}): Promise<UserProfile>;
export declare function login(form: Form<{

@@ -40,3 +134,5 @@ username?: string;

login?: boolean;
} & FormSubmitCallback): Promise<UserProfile | "SUCCESS: The account has been created. User's signup confirmation is required." | 'SUCCESS: The account has been created.'>;
} & {
progress?: ProgressCallback;
}): Promise<UserProfile | "SUCCESS: The account has been created. User's signup confirmation is required." | 'SUCCESS: The account has been created.'>;
export declare function disableAccount(): Promise<'SUCCESS: account has been disabled.'>;

@@ -50,6 +146,6 @@ export declare function resetPassword(form: Form<{

code: string;
}>): Promise<'SUCCESS: Verification code has been sent.' | 'SUCCESS: "phone_number" is verified.'>;
}>): Promise<string>;
export declare function verifyEmail(form?: Form<{
code: string;
}>): Promise<'SUCCESS: Verification code has been sent.' | 'SUCCESS: "email" is verified.'>;
}>): Promise<string>;
export declare function forgotPassword(form: Form<{

@@ -56,0 +152,0 @@ email: string;

import SkapiError from '../main/error';
import { CognitoUserAttribute, CognitoUser, AuthenticationDetails, CognitoUserPool } from 'amazon-cognito-identity-js';
import validator from '../utils/validator';
import { request } from './request';
import { MD5 } from '../utils/utils';
import { request } from '../utils/network';
import { MD5, fromBase62 } from '../utils/utils';
let cognitoUser = null;

@@ -11,2 +11,65 @@ export let userPool = null;

}
function map_ticket_obj(t) {
let mapper = {
"tkid": 'ticket_id',
"cond": 'condition',
"actn": 'action',
"cnt": 'count',
"ttl": 'time_to_live',
"stmp": 'timestamp',
'plch': 'placeholder',
'hash': 'hash',
'desc': 'description',
};
let new_obj = {};
for (let k in t) {
if (k === 'tkid') {
let tkid = t[k].split('#');
if (tkid.length === 1) {
new_obj['ticket_id'] = tkid[0];
continue;
}
new_obj['ticket_id'] = tkid[1];
new_obj['consume_id'] = tkid[2];
new_obj['user_id'] = tkid[3];
if (!t.stmp) {
new_obj['timestamp'] = fromBase62(tkid[2].slice(0, -4));
}
}
else if (mapper[k]) {
new_obj[mapper[k]] = t[k];
}
else {
new_obj[k] = t[k];
}
}
return new_obj;
}
export async function consumeTicket(params) {
if (!params.ticket_id) {
throw new SkapiError('Ticket ID is required.', { code: 'INVALID_PARAMETER' });
}
let ticket_id = params.ticket_id;
await this.__connection;
let resp = await request.bind(this)(`https://${this.service.slice(0, 4)}.skapi.dev/auth/consume/${this.service}/${this.owner}/${ticket_id}`, params, { auth: true });
return map_ticket_obj(resp);
}
export async function getTickets(params, fetchOptions) {
await this.__connection;
let tickets = await request.bind(this)('ticket', Object.assign({ exec: 'list' }, params || {}), { auth: true, fetchOptions });
tickets.list = tickets.list.map(map_ticket_obj);
return tickets;
}
export async function getConsumedTickets(params, fetchOptions) {
await this.__connection;
let tickets = await request.bind(this)('ticket', Object.assign({ exec: 'consumed' }, params || {}), { auth: true, fetchOptions });
tickets.list = tickets.list.map(map_ticket_obj);
return tickets;
}
export async function registerTicket(params) {
return request.bind(this)('register-ticket', Object.assign({ exec: 'reg' }, params), { auth: true });
}
export async function unregisterTicket(params) {
return request.bind(this)('register-ticket', Object.assign({ exec: 'unreg' }, params), { auth: true });
}
export function authentication() {

@@ -146,45 +209,32 @@ if (!userPool)

}
let respond = (session) => {
let idToken = session.getIdToken().payload;
if (idToken['custom:service'] !== this.service) {
cognitoUser.signOut();
this.session = null;
rej(new SkapiError('Invalid session.', { code: 'INVALID_REQUEST' }));
return;
}
this.session = session;
normalizeUserAttributes(idToken);
res(session);
};
if (refreshToken || !session.isValid()) {
let signedOut = false;
try {
let idToken = session.getIdToken().payload;
if (idToken['custom:service'] !== this.service) {
cognitoUser.signOut();
this.session = null;
signedOut = true;
res(null);
cognitoUser.refreshSession(session.getRefreshToken(), (refreshErr, refreshedSession) => {
if (refreshErr) {
rej(refreshErr);
}
}
catch (err) {
}
if (!signedOut) {
cognitoUser.refreshSession(session.getRefreshToken(), (refreshErr, refreshedSession) => {
if (refreshErr)
rej(refreshErr);
else {
if (refreshedSession.isValid()) {
return respond(refreshedSession);
}
else {
if (refreshedSession.isValid()) {
this.session = refreshedSession;
normalizeUserAttributes(refreshedSession.getIdToken().payload);
res(refreshedSession);
}
else {
rej(new SkapiError('Invalid session.', { code: 'INVALID_REQUEST' }));
return;
}
rej(new SkapiError('Invalid session.', { code: 'INVALID_REQUEST' }));
return;
}
});
}
}
});
}
else {
let idToken = session.getIdToken().payload;
if (idToken['custom:service'] !== this.service) {
cognitoUser.signOut();
this.session = null;
res(null);
}
else {
this.session = session;
normalizeUserAttributes(idToken);
res(session);
}
return respond(session);
}

@@ -197,3 +247,3 @@ });

throw new SkapiError('E-Mail is required.', { code: 'INVALID_PARAMETER' });
let username = this.service + '-' + MD5.hash(email);
let username = email.includes(this.service + '-') ? email : this.service + '-' + MD5.hash(email);
return {

@@ -342,2 +392,20 @@ cognitoUser: new CognitoUser({

}
export async function jwtLogin(params) {
validator.Params(params, {
idToken: 'string',
clientId: 'string',
keyUrl: (v) => validator.Url(v),
provider: 'string',
nonce: 'string'
}, ['idToken', 'keyUrl', 'clientId']);
let { hashedPassword, username, email } = await request.bind(this)("jwt-login", params);
try {
return login.bind(this)({ username: username, password: hashedPassword, email });
}
catch (err) {
if (err?.code === 'INCORRECT_USERNAME_OR_PASSWORD') {
throw new SkapiError('User has migrated the account. Login with the service email and password.', { code: 'INVALID_REQUEST' });
}
}
}
export async function login(form) {

@@ -347,8 +415,21 @@ await this.logout();

username: 'string',
email: (v) => validator.Email(v),
password: (v) => validator.Password(v)
}, ['email', 'password']);
email: 'string',
password: 'string'
}, ['password']);
if (params.email) {
try {
validator.Email(params.email);
}
catch (err) {
params.username = params.email;
delete params.email;
}
}
if (!params.username && !params.email) {
throw new SkapiError('Least one of "username" or "email" is required.', { code: 'INVALID_PARAMETER' });
}
return authentication.bind(this)().authenticateUser(params.username || params.email, params.password);
}
export async function signup(form, option) {
let is_admin = await checkAdmin.bind(this)();
let params = validator.Params(form || {}, {

@@ -369,5 +450,11 @@ username: 'string',

access_group: 'number',
misc: 'string'
}, ['email', 'password']);
let is_admin = await checkAdmin.bind(this)();
misc: 'string',
picture: (v) => validator.Url(v),
profile: (v) => validator.Url(v),
family_name: 'string',
given_name: 'string',
middle_name: 'string',
nickname: 'string',
website: (v) => validator.Url(v),
}, is_admin ? ['email'] : ['email', 'password']);
let admin_creating_account = is_admin && params.service && this.service !== params.service;

@@ -377,3 +464,3 @@ if (admin_creating_account) {

}
else {
else if (!is_admin) {
if (params.access_group) {

@@ -417,3 +504,3 @@ throw new SkapiError('Only admins can set "access_group" parameter.', { code: 'INVALID_PARAMETER' });

let signup_confirmation = option?.signup_confirmation || false;
if (admin_creating_account && signup_confirmation) {
if (admin_creating_account && signup_confirmation && params?.password) {
throw new SkapiError('Admins cannot create an account with "option.signup_confirmation" option.', { code: 'INVALID_PARAMETER' });

@@ -430,16 +517,16 @@ }

}
let resp = await request.bind(this)("signup", params, { auth: admin_creating_account });
if (signup_confirmation) {
let u = await authentication.bind(this)().createCognitoUser(params.username || params.email);
cognitoUser = u.cognitoUser;
this.__request_signup_confirmation = u.cognitoUsername;
return "SUCCESS: The account has been created. User's signup confirmation is required.";
let resp = await request.bind(this)("signup", params, { auth: is_admin });
if (!is_admin) {
if (signup_confirmation) {
let u = await authentication.bind(this)().createCognitoUser(params.username || params.email);
cognitoUser = u.cognitoUser;
this.__request_signup_confirmation = u.cognitoUsername;
return "SUCCESS: The account has been created. User's signup confirmation is required.";
}
if (logUser) {
return login.bind(this)({ email: params.username || params.email, password: params.password });
}
return 'SUCCESS: The account has been created.';
}
if (logUser && !admin_creating_account) {
return login.bind(this)({ email: params.username || params.email, password: params.password });
}
if (admin_creating_account) {
return resp;
}
return 'SUCCESS: The account has been created.';
return resp;
}

@@ -614,3 +701,10 @@ export async function disableAccount() {

birthdate_public: 'boolean',
misc: 'string'
misc: 'string',
picture: (v) => validator.Url(v),
profile: (v) => validator.Url(v),
family_name: 'string',
given_name: 'string',
middle_name: 'string',
nickname: 'string',
website: (v) => validator.Url(v),
});

@@ -714,2 +808,3 @@ if (params && typeof params === 'object' && !Object.keys(params).length) {

'birthdate': (v) => validator.Birthdate(v),
'subscribers': 'number',
'timestamp': 'number',

@@ -772,5 +867,2 @@ 'access_group': 'number',

}
if (params.searchFor === 'access_group') {
params.searchFor = 'group';
}
if (typeof params?.value === 'string' && !params?.value) {

@@ -801,1 +893,2 @@ throw new SkapiError('Value should not be an empty string.', { code: 'INVALID_PARAMETER' });

}
//# sourceMappingURL=user.js.map

@@ -29,3 +29,3 @@ export type Condition = 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'ne' | '>' | '>=' | '<' | '<=' | '=' | '!=';

subscription?: boolean;
} | string;
};
reference?: {

@@ -89,9 +89,4 @@ record_id?: string;

ip: string;
group: number;
};
export type FormSubmitCallback = {
response?(response: any): any;
onerror?(error: Error): any;
formData?(formData: FormData): Promise<FormData> | FormData;
progress: ProgressCallback;
};
export type Form<T> = HTMLFormElement | FormData | SubmitEvent | T;

@@ -126,2 +121,6 @@ export type Newsletters = {

misc?: string;
picture?: string;
profile?: string;
website?: string;
nickname?: string;
};

@@ -153,2 +152,3 @@ export type UserProfile = {

subscribers?: number;
records?: number;
timestamp: number;

@@ -160,2 +160,6 @@ service: string;

locale: string;
picture?: string;
profile?: string;
website?: string;
nickname?: string;
};

@@ -162,0 +166,0 @@ export type ProgressCallback = (e: {

export {};
//# sourceMappingURL=Types.js.map

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

import { Form } from "../Types";
declare class MD5 {

@@ -15,8 +14,9 @@ private static readonly alphabet;

}
declare function toBase62(num: number): string;
declare function fromBase62(chars: any): any;
declare function generateRandom(length?: number): string;
declare function extractFormMeta(form: Form<any>): {
meta: {};
declare function extractFormData(form: any): {
data: {};
files: any[];
to_bin: any[];
};
export { extractFormMeta, MD5, generateRandom };
export { fromBase62, toBase62, extractFormData, MD5, generateRandom };

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

import SkapiError from "../main/error";
class MD5 {

@@ -138,2 +139,17 @@ static hash(str) {

MD5.alphabet = '0123456789abcdef';
function toBase62(num) {
const base62Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
if (num === 0)
return base62Chars[0];
let result = '';
while (num > 0) {
result = base62Chars[num % 62] + result;
num = Math.floor(num / 62);
}
return result;
}
function fromBase62(chars) {
let charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
return chars.split('').reverse().reduce((prev, curr, i) => prev + (charset.indexOf(curr) * (62 ** i)), 0);
}
function generateRandom(length = 6) {

@@ -150,70 +166,74 @@ let result = '';

}
function extractFormMeta(form) {
function appendData(meta, key, val) {
let fchar = key.slice(0, 1);
let lchar = key.slice(-1);
if (fchar === '.') {
key = key.slice(1);
function extractFormData(form) {
let data = {};
let files = [];
function appendData(data, key, val) {
let keys = key.split('[').map(k => {
let key = k.replace(']', '');
if (key.match(/\d+/) && !key.includes('.')) {
key = Number(key);
}
else if (key[0] === '"' && key[key.length - 1] === '"' || key[0] === "'" && key[key.length - 1] === "'") {
key = key.replace(/"/g, '').replace(/'/g, '');
}
return key;
});
let obj = data;
if (typeof keys[0] === 'number') {
throw new SkapiError('Form key cannot start with an array index.', { code: 'INVALID_REQUEST' });
}
if (lchar === '.') {
key = key.slice(0, -1);
}
if (key.includes('.')) {
let nestKey = key.split('.');
key = nestKey.pop();
for (let k of nestKey) {
if (!k) {
continue;
for (let i = 0; i < keys.length; i++) {
let k = keys[i];
if (i < keys.length - 1) {
if (obj[k] === undefined) {
let next = keys[i + 1];
if (typeof next === 'number') {
obj[k] = [];
}
else {
obj[k] = {};
}
}
if (!meta.hasOwnProperty(k)) {
meta[k] = {};
obj = obj[k];
}
else {
if (obj[k] === undefined) {
obj[k] = val;
}
meta = meta[k];
else if (Array.isArray(obj[k])) {
obj[k].push(val);
}
else {
obj[k] = [obj[k], val];
}
}
}
if (meta.hasOwnProperty(key)) {
if (Array.isArray(meta[key])) {
meta[key].push(val);
}
function handleFile(files, name, v) {
if (v instanceof File) {
files.push({ name, file: v });
}
else if (v instanceof FileList) {
if (v && v.length > 0) {
for (let idx = 0; idx <= v.length - 1; idx++) {
let file = v.item(idx);
if (file) {
files.push({ name, file });
}
}
}
else {
meta[key] = [meta[key], val];
}
}
else {
meta[key] = val;
}
}
let to_bin = [];
if (form instanceof FormData) {
let meta = {};
let totalFileSize = 0;
let files = [];
for (let pair of form.entries()) {
let name = pair[0];
let v = pair[1];
if (v instanceof File) {
if ((totalFileSize + v.size) > 4000000) {
to_bin.push({ name, file: v });
continue;
}
totalFileSize += v.size;
files.push({ name, file: v });
if ((v instanceof File) || (v instanceof FileList)) {
handleFile(files, name, v);
}
else if (v instanceof FileList) {
if (v && v.length > 0) {
for (let idx = 0; idx <= v.length - 1; idx++) {
if ((totalFileSize + v.item(idx).size) > 4000000) {
to_bin.push({ name, file: v.item(idx) });
continue;
}
totalFileSize += v.item(idx).size;
files.push({ name, file: v.item(idx) });
}
}
}
else {
appendData(meta, name, v);
appendData(data, name, v);
}
}
return { meta, files, to_bin };
return { data, files };
}

@@ -224,11 +244,15 @@ if (form instanceof SubmitEvent) {

if (form instanceof HTMLFormElement) {
let meta = {};
let files = [];
let totalFileSize = 0;
let inputs = form.querySelectorAll('input');
let selects = form.querySelectorAll('select');
let textarea = form.querySelectorAll('textarea');
for (let idx = 0; idx < selects.length; idx++) {
let i = selects[idx];
if (i.name) {
appendData(data, i.name, i.value);
}
}
for (let idx = 0; idx < textarea.length; idx++) {
let i = textarea[idx];
if (i.name) {
appendData(meta, i.name, i.value);
appendData(data, i.name, i.value);
}

@@ -241,3 +265,3 @@ }

if (i.value) {
appendData(meta, i.name, Number(i.value));
appendData(data, i.name, Number(i.value));
}

@@ -248,9 +272,9 @@ }

if (i.value === '' && i.type === 'checkbox' || i.value === 'on' || i.value === 'true') {
appendData(meta, i.name, true);
appendData(data, i.name, true);
}
else if (i.value === 'false') {
appendData(meta, i.name, false);
appendData(data, i.name, false);
}
else if (i.value) {
appendData(meta, i.name, i.value);
appendData(data, i.name, i.value);
}

@@ -260,10 +284,7 @@ }

if (i.value === '' || i.value === 'on' || i.value === 'true') {
appendData(meta, i.name, false);
appendData(data, i.name, false);
}
else if (i.value === 'false') {
appendData(meta, i.name, true);
appendData(data, i.name, true);
}
else {
appendData(meta, i.name, undefined);
}
}

@@ -273,21 +294,21 @@ }

if (i.files && i.files.length > 0) {
for (let idx = 0; idx <= i.files.length - 1; idx++) {
if ((totalFileSize + i.files.item(idx).size) > 4000000) {
to_bin.push({ name: i.name, file: i.files.item(idx) });
continue;
}
totalFileSize += i.files.item(idx).size;
files.push({ name: i.name, file: i.files.item(idx) });
}
handleFile(files, i.name, i.files);
}
}
else {
appendData(meta, i.name, i.value);
appendData(data, i.name, i.value);
}
}
}
return { meta, files, to_bin };
function sizeof(object) {
return new Blob([JSON.stringify(object)]).size;
}
if (sizeof(data) > 2 * 1024 * 1024) {
throw new SkapiError('Data should not exceed 2MB', { code: 'INVALID_REQUEST' });
}
return { data, files };
}
return null;
}
export { extractFormMeta, MD5, generateRandom };
export { fromBase62, toBase62, extractFormData, MD5, generateRandom };
//# sourceMappingURL=utils.js.map

@@ -8,3 +8,3 @@ declare function UserId(id: string, param?: string): string;

declare function specialChars(string: string | string[], p?: string, allowPeriods?: boolean, allowWhiteSpace?: boolean): string | string[];
declare function Params(params: any, struct: Record<string, any>, required?: string[] | null, bypassCheck?: string[] | null, _parentKey?: string | null): any;
declare function Params(params: any, struct: Record<string, any>, required?: string[]): any;
declare const _default: {

@@ -11,0 +11,0 @@ UserId: typeof UserId;

import SkapiError from '../main/error';
import { extractFormMeta } from './utils';
import { extractFormData } from './utils';
function UserId(id, param = 'User ID') {

@@ -151,141 +151,115 @@ let uuid_regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i;

}
function Params(params, struct, required = null, bypassCheck = [], _parentKey = null) {
if (Array.isArray(bypassCheck)) {
bypassCheck = bypassCheck.concat([
'service',
'owner',
]);
}
function isObjectWithKeys(obj) {
if (obj instanceof Promise) {
throw new SkapiError('Parameter should not be a promise', { code: 'INVALID_PARAMETER' });
}
return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length;
}
function isEmptyObject(obj) {
return obj && typeof obj === 'object' && !Array.isArray(obj) && !Object.keys(obj).length;
}
let _params = params;
let val;
let errToThrow = null;
let isInvalid = _parentKey ? ` in "${_parentKey}" is invalid.` : '. Parameter should be type <object>.';
if (_parentKey === null) {
if (isObjectWithKeys(_params)) {
if (_params instanceof HTMLFormElement || _params instanceof FormData || _params instanceof SubmitEvent) {
_params = extractFormMeta(params)?.meta;
function Params(params, struct, required = []) {
let p = extractFormData(params)?.data || params;
struct.service = 'string';
struct.owner = 'string';
let toCheck = {};
for (let s in struct) {
if (p && typeof p === 'object' && !Array.isArray(p) && p.hasOwnProperty(s)) {
if (typeof p[s] === 'function') {
toCheck[s] = p[s];
}
else {
_params = JSON.parse(JSON.stringify(params));
}
for (let k in _params) {
if (!struct.hasOwnProperty(k) && Array.isArray(bypassCheck) && !bypassCheck.includes(k)) {
throw new SkapiError(`Key name "${k}" is invalid in parameter.`, { code: 'INVALID_PARAMETER' });
try {
toCheck[s] = JSON.parse(JSON.stringify(p[s]));
}
}
if (Array.isArray(required) && required.length) {
for (let k of required) {
if (!Object.keys(_params).includes(k)) {
throw new SkapiError(`Key "${k}" is required in parameter.`, { code: 'INVALID_PARAMETER' });
}
catch (err) {
toCheck[s] = p[s];
}
}
}
else if (isEmptyObject(_params) || typeof _params === 'undefined') {
let defaults = {};
for (let s in struct) {
let structValue = struct[s];
if (Array.isArray(structValue) && typeof structValue[structValue.length - 1] === 'function')
defaults[s] = structValue[structValue.length - 1]();
}
return Object.keys(defaults).length ? defaults : _params;
}
if (_params === null) {
return null;
}
}
if (isObjectWithKeys(struct) && isObjectWithKeys(_params)) {
for (let s in struct) {
let structValue = struct[s];
if (_params.hasOwnProperty(s) && _params[s] === null) {
_params[s] = null;
}
else if (_params.hasOwnProperty(s) && typeof _params[s] !== 'undefined') {
_params[s] = Params(_params[s], structValue, null, null, s);
}
else {
let defaultSetter = Array.isArray(structValue) &&
typeof structValue[structValue.length - 1] === 'function' ? structValue[structValue.length - 1] : null;
if (defaultSetter) {
let def = defaultSetter();
if (def !== undefined) {
_params[s] = def;
}
}
}
}
val = _params;
try {
return checkParams(toCheck, struct, required);
}
else if (Array.isArray(struct)) {
catch (err) {
throw new SkapiError(err, { code: 'INVALID_PARAMETER' });
}
}
function checkParams(params, struct, required = [], _parentKey = null) {
function isObjectWithKeys(obj) {
return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length;
}
function isArrayWithValues(arr) {
return Array.isArray(arr) && arr.length;
}
if (_parentKey === null && !isObjectWithKeys(struct)) {
throw 'Argument "struct" is required.';
}
let invalid_in = _parentKey !== null ? ` in key "${_parentKey}" is invalid.` : '. Parameter should be type <object>.';
if (isArrayWithValues(struct)) {
let should_be = struct.map(s => (['string', 'number', 'boolean', 'object', 'array'].includes(s) ? `Type<${s}>` : JSON.stringify(s, null, 2))).join(' or ');
let pass = false;
let val;
for (let s of struct) {
try {
if (typeof _params !== undefined && typeof s !== 'function') {
val = Params(_params, s, null, null, _parentKey);
}
val = checkParams(params, s, required, _parentKey);
pass = true;
break;
}
catch (err) {
if (typeof err === 'string' && err.substring(0, 6) === 'BREAK:') {
err = err.substring(6);
let errMsg = err.split(':');
errToThrow = new SkapiError(errMsg[1], { code: errMsg[0] });
break;
}
else {
errToThrow = err;
}
pass = false;
}
}
if (!pass) {
throw `Invalid type "${typeof params}"${invalid_in} Should be: ${should_be}`;
}
return val;
}
else if (typeof struct === 'function') {
return struct(_params);
}
else if (typeof struct === 'string') {
if (Array.isArray(_params)) {
if (struct !== 'array') {
throw new SkapiError(`Invalid type "${typeof _params}"${isInvalid}`, { code: 'INVALID_PARAMETER' });
}
for (let p of _params) {
if (!['number', 'string', 'boolean'].includes(typeof p) && p !== null) {
throw new SkapiError(`Invalid type "${typeof p}" in "${_parentKey}" array value.`, { code: 'INVALID_PARAMETER' });
if (isObjectWithKeys(params)) {
if (isObjectWithKeys(struct)) {
for (let k in struct) {
let key = (_parentKey === null ? '' : _parentKey) + (_parentKey !== null ? '[' + k + ']' : k);
if (!params.hasOwnProperty(k)) {
if (required.includes(key)) {
throw `Key "${key}" is required.`;
}
if (isArrayWithValues(struct[k]) && typeof struct[k][struct[k].length - 1] === 'function') {
params[k] = struct[k][struct[k].length - 1]();
}
}
}
val = _params;
}
else if (!['number', 'string', 'boolean', 'array', 'function'].includes(struct)) {
if (_params === struct) {
val = _params;
if ('object' === struct) {
return params;
}
else if (typeof struct === 'function') {
return struct(params);
}
for (let k in params) {
let parentKey = (_parentKey === null ? '' : _parentKey) + (_parentKey !== null ? '[' + k + ']' : k);
if (!isArrayWithValues(struct) && !struct.hasOwnProperty(k)) {
continue;
}
if (isArrayWithValues(params[k])) {
if (struct[k] === 'array') {
continue;
}
if (typeof struct[k] === 'function') {
params[k] = struct[k](params[k]);
continue;
}
for (let i = 0; i < params[k].length; i++) {
params[k][i] = checkParams(params[k][i], struct[k], required, parentKey + `[${i}]`);
}
}
else {
throw new SkapiError(`Value: ${_params}${isInvalid}`, { code: 'INVALID_PARAMETER' });
params[k] = checkParams(params[k], struct[k], required, parentKey);
}
}
else if (typeof _params === struct) {
if (struct === 'number') {
if (Math.abs(_params) > 4503599627370496) {
throw `BREAK:INVALID_PARAMETER:"${_parentKey}" integer value should be within -4503599627370496 ~ +4503599627370546.`;
}
}
val = _params;
}
else {
throw new SkapiError(`Value: ${_params}${isInvalid}`, { code: 'INVALID_PARAMETER' });
}
return params;
}
else if (struct === null) {
val = _params;
if (typeof struct === 'function') {
return struct(params);
}
if (val === undefined && errToThrow) {
throw errToThrow;
if (struct === 'array' && Array.isArray(params) || struct === typeof params || params === struct) {
return params;
}
return val;
function isEmptyObject(obj) {
return obj && typeof obj === 'object' && !Array.isArray(obj) && !Object.keys(obj).length;
}
if (params === null || params === undefined || isEmptyObject(params)) {
return params;
}
throw `Invalid type "${typeof params}"${invalid_in} Should be: ${(['string', 'number', 'boolean', 'object', 'array'].includes(struct) ? `Type<${struct}>` : JSON.stringify(struct, null, 2))}`;
}

@@ -302,1 +276,2 @@ export default {

};
//# sourceMappingURL=validator.js.map
{
"name": "skapi-js",
"version": "1.0.5",
"description": "Javascript library for Skapi: Complete JAM Stack, front-end driven serverless backend API service.",
"main": "./dist/skapi.module.js",
"types": "./js/Main.d.ts",
"version": "1.0.64.beta-0",
"description": "Skapi: Backend API Library for HTML frontend.",
"main": "dist/skapi.module.js",
"types": "js/Main.d.ts",
"files": [
"js/",
"dist/"
"js",
"dist"
],
"scripts": {
"build": "npx tsc --project tsconfig.json; npx webpack --config webpack.config.js; cp -r dist playground;",
"dev": "(cd playground; node server.js)"
"build": "npx tsc --project tsconfig.json; npx webpack --config webpack.config.js;"
},

@@ -27,4 +26,5 @@ "repository": {

"devDependencies": {
"amazon-cognito-identity-js": "^5.2.14",
"typescript": "^4.9.4",
"amazon-cognito-identity-js": "^6.3.7",
"ts-loader": "^9.5.1",
"typescript": "^5.3.3",
"webpack": "^5.74.0",

@@ -37,4 +37,6 @@ "webpack-cli": "^4.10.0"

"api",
"jamstack"
"serverless",
"frontend",
"html"
]
}
# Skapi
Skapi is a backend API service that is specially designed for frontend web developers.
Skapi is a backend API Library for HTML Frontend.
Now you can build fullstack web applications directly from your HTML frontend without the need for a backend server deployment.
#### Compatible with both vanilla HTML and SPA projects
### Compatible with both vanilla HTML and SPA projects
No fancy framework or complex deployment required. Just focused on the basics, Skapi is a single JavaScript library fully compatible with vanilla HTML, as well as any frontend frameworks.
#### All-in-One Package
### All-in-One Package
Skapi provides all the backend features you need for your web application out of the box, without the need to set up or maintain multiple services.
Skapi provides all the backend features you need for your web application out of the box, without the need to set up or maintain any backend servers.
#### Simple, Yet Flexible Database
- Authentication
- Database
- File Storage
- CDN
- Automated Email Systems
- Realtime Messaging
- API Bridge for 3rd party API's
- Hosting
Skapi's unique database design combines the best of SQL and noSQL worlds, providing both scalability and flexibility without the need for manual schema design.

@@ -22,3 +29,3 @@ ## Getting Started

1. Signup for an account at [skapi.com](https://www.skapi.com/signup).
2. Log in and create a new service from your [dashboard page](https://www.skapi.com/admin).
2. Log in and create a new service from the `My Services` page.

@@ -31,3 +38,3 @@

#### For HTML projects:
### For HTML projects:

@@ -37,8 +44,4 @@ For vanilla HTML projects, import Skapi in the script tag, and initialize the library.

```html
<!-- index.html -->
<!DOCTYPE html>
<script src="https://cdn.jsdelivr.net/npm/skapi-js@latest/dist/skapi.js"></script>
<!-- Your content goes here -->
<script>

@@ -51,3 +54,3 @@ const skapi = new Skapi('service_id', 'owner_id');

#### For SPA projects:
### For SPA projects:

@@ -82,2 +85,5 @@ To use Skapi in a SPA projects (such as Vue, React, or Angular), you can install skapi-js via npm.

<script src="https://cdn.jsdelivr.net/npm/skapi-js@latest/dist/skapi.js"></script>
<script>
const skapi = new Skapi('service_id', 'owner_id');
</script>

@@ -88,6 +94,2 @@ <form onsubmit='skapi.mock(event).then(ping=>alert(ping.msg))'>

</form>
<script>
const skapi = new Skapi('service_id', 'owner_id');
</script>
```

@@ -99,4 +101,2 @@

Skapi is capable of handling HTML `onsubmit` event directly.
#### For more information, check out our [documentation](https://docs.skapi.com).

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc