initial commit
This commit is contained in:
commit
fb7610845e
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules/**
|
||||||
|
dist/**
|
7
LICENSE.txt
Normal file
7
LICENSE.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Copyright 2023 sati.ac
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
README.md
Normal file
25
README.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# sati-js - javascript client for sati.ac
|
||||||
|
[![NPM version](https://badge.fury.io/js/sati.svg)](https://www.npmjs.com/package/sati)
|
||||||
|
![Downloads](https://img.shields.io/npm/dm/sati.svg?style=flat)
|
||||||
|
|
||||||
|
## usage example
|
||||||
|
```ts
|
||||||
|
const sati = new Sati({
|
||||||
|
token: 'your token here'
|
||||||
|
})
|
||||||
|
await sati.init() // you must call the init method after construction
|
||||||
|
|
||||||
|
const balance = await sati.getBalance()
|
||||||
|
console.log(balance)
|
||||||
|
|
||||||
|
// first argument - task type, second - task parameters
|
||||||
|
// supported tasks: https://sati.ac/docs/tasks
|
||||||
|
const task = await sati.solve('Turnstile', {
|
||||||
|
siteKey: '0x4AAAAAAAHMEd1rGJs9qy-0',
|
||||||
|
pageUrl: 'https://polygon.sati.ac/Turnstile'
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(task, task.result.token)
|
||||||
|
|
||||||
|
sati.close() // you must call close method after you've done
|
||||||
|
```
|
2680
package-lock.json
generated
Normal file
2680
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
45
package.json
Normal file
45
package.json
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"name": "sati",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "next generation anti-captcha",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://git.sati.ac/sati.ac/sati-js"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"sati.ac",
|
||||||
|
"anti-captcha",
|
||||||
|
"anticaptcha",
|
||||||
|
"captcha"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"dist/",
|
||||||
|
"!**/*.tsbuildinfo"
|
||||||
|
],
|
||||||
|
"main": "dist/sati.node.cjs.js",
|
||||||
|
"unpkg": "dist/sati.web.umd.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "rm -rf dist && webpack"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^20.1.1",
|
||||||
|
"@types/ws": "^8.5.4",
|
||||||
|
"ws": "^8.13.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"ts-loader": "^9.4.2",
|
||||||
|
"typescript": "^5.0.4",
|
||||||
|
"webpack": "^5.82.0",
|
||||||
|
"webpack-cli": "^5.1.1"
|
||||||
|
},
|
||||||
|
"types": "./dist/src/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "dist/sati.web.esm.mjs",
|
||||||
|
"require": "dist/sati.web.umd.js",
|
||||||
|
"types": "dist/src/index.d.ts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
109
src/Sati.ts
Normal file
109
src/Sati.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { EventEmitter } from './helpers/EventEmitter'
|
||||||
|
import { SatiError } from './SatiError'
|
||||||
|
import { SatiSocket, SocketState } from './SatiSocket'
|
||||||
|
import { events, methods, tasks, Task } from './types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* high level api wrapper
|
||||||
|
* @example
|
||||||
|
* const sati = new Sati({
|
||||||
|
* token: 'your token here'
|
||||||
|
* })
|
||||||
|
* await sati.init() // you must call the init method after construction
|
||||||
|
*
|
||||||
|
* const task = await sati.solve('Turnstile', {
|
||||||
|
* siteKey: '0x4AAAAAAAHMEd1rGJs9qy-0',
|
||||||
|
* pageUrl: 'https://polygon.sati.ac/Turnstile'
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* console.log(task, task.result.token)
|
||||||
|
*
|
||||||
|
* sati.close() // you must call close method after you've done
|
||||||
|
*/
|
||||||
|
export class Sati extends EventEmitter<events> {
|
||||||
|
private socket: SatiSocket
|
||||||
|
private awaitedTasks: {
|
||||||
|
[ index: number ]: {
|
||||||
|
resolve(data: any): void,
|
||||||
|
reject(reason: any): void
|
||||||
|
}
|
||||||
|
} = Object.create(null)
|
||||||
|
|
||||||
|
/** @param token your api token. get it at https://sati.ac/dashboard */
|
||||||
|
constructor({ token }: { token: string }) {
|
||||||
|
super()
|
||||||
|
this.socket = new SatiSocket(token)
|
||||||
|
this.socket.on('event', ({ type, data }) => {
|
||||||
|
this.emit(type as keyof events, data)
|
||||||
|
})
|
||||||
|
this.socket.on('stateChange', ({ state, error }) => {
|
||||||
|
switch(state) {
|
||||||
|
case SocketState.connected:
|
||||||
|
// as of socket was disconnected, there might be missed events
|
||||||
|
// so we need to recheck the state of each awaited task
|
||||||
|
for(const [ id, awaited ] of Object.entries(this.awaitedTasks)) {
|
||||||
|
this.call('getTask', { id: +id }).then(this.handleTaskResult.bind(this), err => {
|
||||||
|
awaited.reject(err)
|
||||||
|
delete this.awaitedTasks[+id]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
case SocketState.unrecoverable:
|
||||||
|
// socket got an unrecoverable error, so it will never be connected again
|
||||||
|
for(const awaited of Object.values(this.awaitedTasks)) {
|
||||||
|
awaited.reject(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.on('taskUpdate', this.handleTaskResult.bind(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleTaskResult(task: Task) {
|
||||||
|
if(!(task.id in this.awaitedTasks)) return
|
||||||
|
if(task.state !== 'error' && task.state !== 'success') return
|
||||||
|
const awaited = this.awaitedTasks[task.id]
|
||||||
|
|
||||||
|
if(task.state === 'error') {
|
||||||
|
awaited.reject(new SatiError(`unable to solve ${task.type} task #${task.id}`))
|
||||||
|
} else if(task.state === 'success') {
|
||||||
|
awaited.resolve(task)
|
||||||
|
}
|
||||||
|
delete this.awaitedTasks[task.id]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** connects to the socket, must be called before any other methods */
|
||||||
|
public async init() {
|
||||||
|
await this.socket.connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** closes the socket */
|
||||||
|
public close() {
|
||||||
|
this.socket.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** calls the api method, use top-level wrappers for them instead */
|
||||||
|
public async call<M extends keyof methods>(method: M, data: methods[M]['request']): Promise<methods[M]['response']> {
|
||||||
|
const resp = await this.socket.send('call', { method, data })
|
||||||
|
|
||||||
|
if(!resp.success) {
|
||||||
|
throw new SatiError(resp.data.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates task, then waits for the result
|
||||||
|
* @throws {SatiError} if unable to solve
|
||||||
|
*/
|
||||||
|
public async solve<T extends keyof tasks>(type: T, data: tasks[T]['params']): Promise<Task<T, 'success'>> {
|
||||||
|
const task = await this.call('createTask', { type, data })
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.awaitedTasks[task.id] = { resolve, reject }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getBalance() {
|
||||||
|
return (await this.call('getBalance', {})).balance
|
||||||
|
}
|
||||||
|
}
|
5
src/SatiError.ts
Normal file
5
src/SatiError.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export class SatiError extends Error {
|
||||||
|
constructor(msg: string) {
|
||||||
|
super(`sati: ${msg}`)
|
||||||
|
}
|
||||||
|
}
|
147
src/SatiSocket.ts
Normal file
147
src/SatiSocket.ts
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
import { EventEmitter } from './helpers/EventEmitter'
|
||||||
|
import { SocketAdapter } from '%env%'
|
||||||
|
import { SatiError } from './SatiError'
|
||||||
|
import { endpoint } from './config'
|
||||||
|
|
||||||
|
interface WebSocketMessage {
|
||||||
|
id: number
|
||||||
|
type: string
|
||||||
|
data: any
|
||||||
|
to?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SocketState {
|
||||||
|
connected,
|
||||||
|
disconnected,
|
||||||
|
unrecoverable
|
||||||
|
}
|
||||||
|
|
||||||
|
/** low-level api wrapper */
|
||||||
|
export class SatiSocket extends EventEmitter<{
|
||||||
|
event: {
|
||||||
|
type: string,
|
||||||
|
data: any
|
||||||
|
},
|
||||||
|
stateChange: {
|
||||||
|
state: SocketState,
|
||||||
|
error: Error | null
|
||||||
|
}
|
||||||
|
}> {
|
||||||
|
private token: string
|
||||||
|
private socket: SocketAdapter | null = null
|
||||||
|
private error: Error | null = null
|
||||||
|
private state: SocketState = SocketState.disconnected
|
||||||
|
|
||||||
|
private idCounter = 0
|
||||||
|
private awaitedMessages: Record<number, {
|
||||||
|
resolve: (data: any) => void
|
||||||
|
reject: (error: any) => void
|
||||||
|
}> = Object.create(null)
|
||||||
|
private queue: [(data: any) => void, string, any][] = []
|
||||||
|
|
||||||
|
constructor(token: string) {
|
||||||
|
super()
|
||||||
|
this.token = token
|
||||||
|
}
|
||||||
|
|
||||||
|
private setState(state: SocketState, error: Error | null = null) {
|
||||||
|
this.state = state
|
||||||
|
this.error = error
|
||||||
|
this.emit('stateChange', { state, error })
|
||||||
|
}
|
||||||
|
|
||||||
|
public async connect() {
|
||||||
|
if(this.socket || this.state !== SocketState.disconnected) return;
|
||||||
|
this.idCounter = 0
|
||||||
|
this.socket = new SocketAdapter(endpoint)
|
||||||
|
this.socket.once('close', this.onSocketClose.bind(this))
|
||||||
|
this.socket.on('message', this.onMessage.bind(this))
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
this.socket?.once('open', res)
|
||||||
|
this.socket?.once('error', rej)
|
||||||
|
})
|
||||||
|
const resp = await this.unqueuedSend('auth', { token: this.token })
|
||||||
|
if(!resp.success) {
|
||||||
|
const error = new SatiError('invalid auth token')
|
||||||
|
this.setState(SocketState.unrecoverable, error)
|
||||||
|
this.socket?.close()
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
this.setState(SocketState.connected)
|
||||||
|
await this.flushQueue()
|
||||||
|
}
|
||||||
|
|
||||||
|
public close() {
|
||||||
|
this.setState(SocketState.unrecoverable, new SatiError('socket was closed'))
|
||||||
|
this.socket?.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private flushQueue() {
|
||||||
|
const promises = []
|
||||||
|
for(const [ cb, type, data ] of this.queue) {
|
||||||
|
promises.push(this.unqueuedSend(type, data).then(cb))
|
||||||
|
}
|
||||||
|
return Promise.all(promises)
|
||||||
|
}
|
||||||
|
|
||||||
|
private onSocketClose() {
|
||||||
|
this.socket = null
|
||||||
|
|
||||||
|
for(const awaited of Object.values(this.awaitedMessages)) {
|
||||||
|
// we don't want to resend them, because it may cause task double-creation
|
||||||
|
awaited.reject(new SatiError('socket gone'))
|
||||||
|
}
|
||||||
|
this.awaitedMessages = Object.create(null)
|
||||||
|
|
||||||
|
if(this.state !== SocketState.unrecoverable) {
|
||||||
|
this.setState(SocketState.disconnected)
|
||||||
|
setTimeout(() => {
|
||||||
|
this.connect().catch(err => {
|
||||||
|
console?.error?.('sati: error while reconnecting:', err)
|
||||||
|
})
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async unqueuedSend(type: string, data: any) {
|
||||||
|
if(this.state === SocketState.unrecoverable) throw this.error
|
||||||
|
if(!this.socket) return;
|
||||||
|
const id = ++this.idCounter
|
||||||
|
|
||||||
|
this.socket.send(JSON.stringify({ id, type, data }))
|
||||||
|
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
this.awaitedMessages[id] = { resolve, reject }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public send(type: string, data: any) {
|
||||||
|
switch(this.state) {
|
||||||
|
case SocketState.connected:
|
||||||
|
return this.unqueuedSend(type, data)
|
||||||
|
case SocketState.disconnected:
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.queue.push([ resolve, type, data ])
|
||||||
|
})
|
||||||
|
case SocketState.unrecoverable:
|
||||||
|
throw this.error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onMessage(message: string) {
|
||||||
|
const parsed: WebSocketMessage = JSON.parse(message)
|
||||||
|
if(parsed.type === 'event') {
|
||||||
|
if(parsed.data.type === 'tokenReissue') {
|
||||||
|
this.setState(SocketState.unrecoverable, new SatiError('token was reissued'))
|
||||||
|
this.socket?.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('event', parsed.data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(parsed.to && parsed.to in this.awaitedMessages) {
|
||||||
|
this.awaitedMessages[parsed.to].resolve(parsed.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
src/config.ts
Normal file
1
src/config.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const endpoint = 'wss://api.sati.ac/ws'
|
36
src/env/node/index.ts
vendored
Normal file
36
src/env/node/index.ts
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { WebSocket, RawData } from 'ws'
|
||||||
|
import { SocketAdapter } from '../../helpers/SocketAdapter'
|
||||||
|
|
||||||
|
class NodeSocketAdapter extends SocketAdapter {
|
||||||
|
private socket: WebSocket
|
||||||
|
|
||||||
|
constructor(url: string) {
|
||||||
|
super()
|
||||||
|
this.socket = new WebSocket(url)
|
||||||
|
this.socket.on('message', this.emitMessage.bind(this))
|
||||||
|
this.socket.on('error', err => this.emit('error', err))
|
||||||
|
this.socket.on('open', () => this.emit('open', null))
|
||||||
|
this.socket.on('close', () => this.emit('close', null))
|
||||||
|
}
|
||||||
|
|
||||||
|
public send(message: string) {
|
||||||
|
this.socket.send(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
public close() {
|
||||||
|
this.socket.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private emitMessage(message: RawData) {
|
||||||
|
if(Array.isArray(message)) {
|
||||||
|
message = Buffer.concat(message)
|
||||||
|
}
|
||||||
|
if(message instanceof ArrayBuffer) {
|
||||||
|
message = Buffer.from(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('message', message.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { NodeSocketAdapter as SocketAdapter }
|
23
src/env/web/index.ts
vendored
Normal file
23
src/env/web/index.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { SocketAdapter } from '../../helpers/SocketAdapter'
|
||||||
|
|
||||||
|
class BrowserSocketAdapter extends SocketAdapter {
|
||||||
|
private socket: WebSocket
|
||||||
|
constructor(url: string) {
|
||||||
|
super()
|
||||||
|
this.socket = new WebSocket(url)
|
||||||
|
this.socket.addEventListener('message', e => this.emit('message', e.data))
|
||||||
|
this.socket.addEventListener('error', e => this.emit('error', e))
|
||||||
|
this.socket.addEventListener('open', () => this.emit('open', null))
|
||||||
|
this.socket.addEventListener('close', () => this.emit('close', null))
|
||||||
|
}
|
||||||
|
|
||||||
|
public send(message: string) {
|
||||||
|
this.socket.send(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
public close() {
|
||||||
|
this.socket.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { BrowserSocketAdapter as SocketAdapter }
|
35
src/helpers/EventEmitter.ts
Normal file
35
src/helpers/EventEmitter.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* fully typed node-like event emitter
|
||||||
|
* usage: `EventEmitter<{ event: eventDataType }>`
|
||||||
|
*/
|
||||||
|
export class EventEmitter<T extends {} = {}> {
|
||||||
|
private listeners: { [E in keyof T]: Set<((data: T[E]) => void)> } = Object.create(null)
|
||||||
|
|
||||||
|
public on<E extends keyof T>(event: E, listener: ((data: T[E]) => void)) {
|
||||||
|
this.listeners[event] ||= new Set()
|
||||||
|
this.listeners[event].add(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
public off<E extends keyof T>(event: E, listener: ((data: T[E]) => void)) {
|
||||||
|
this.listeners[event]?.delete(listener)
|
||||||
|
if(this.listeners[event]?.size === 0) {
|
||||||
|
delete this.listeners[event]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public once<E extends keyof T>(event: E, listener: ((data: T[E]) => void)) {
|
||||||
|
const wrapped = (data: T[E]) => {
|
||||||
|
this.off(event, wrapped)
|
||||||
|
listener(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.on(event, wrapped)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected emit<E extends keyof T>(event: E, data: T[E]) {
|
||||||
|
if(!this.listeners[event]) return
|
||||||
|
for(const listener of this.listeners[event]) {
|
||||||
|
listener(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/helpers/SocketAdapter.ts
Normal file
16
src/helpers/SocketAdapter.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { EventEmitter } from '../helpers/EventEmitter'
|
||||||
|
|
||||||
|
export interface SocketAdapterConstructor {
|
||||||
|
new(url: string): SocketAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
/** cross-platform websocket interface */
|
||||||
|
export abstract class SocketAdapter extends EventEmitter<{
|
||||||
|
message: string,
|
||||||
|
open: null,
|
||||||
|
close: null,
|
||||||
|
error: any
|
||||||
|
}> {
|
||||||
|
public abstract send(message: string): void
|
||||||
|
public abstract close(): void
|
||||||
|
}
|
3
src/index.ts
Normal file
3
src/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './Sati'
|
||||||
|
export * from './SatiError'
|
||||||
|
export type { Task } from './types'
|
72
src/types.ts
Normal file
72
src/types.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
export type tasks = {
|
||||||
|
Turnstile: {
|
||||||
|
params: {
|
||||||
|
siteKey: string,
|
||||||
|
pageUrl: string,
|
||||||
|
action?: string,
|
||||||
|
cData?: string
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
token: string
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ReCaptcha2: {
|
||||||
|
params: {
|
||||||
|
siteKey: string,
|
||||||
|
pageUrl: string
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
token: string
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FunCaptcha: {
|
||||||
|
params: {
|
||||||
|
siteKey: string,
|
||||||
|
pageUrl: string,
|
||||||
|
data: Record<string, string>
|
||||||
|
serviceUrl?: string
|
||||||
|
},
|
||||||
|
result: {
|
||||||
|
token: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type methods = {
|
||||||
|
getBalance: {
|
||||||
|
request: {},
|
||||||
|
response: {
|
||||||
|
balance: string
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createTask: {
|
||||||
|
request: {
|
||||||
|
type: keyof tasks,
|
||||||
|
data: tasks[keyof tasks]['params']
|
||||||
|
},
|
||||||
|
response: Task
|
||||||
|
},
|
||||||
|
getTask: {
|
||||||
|
request: {
|
||||||
|
id: number
|
||||||
|
},
|
||||||
|
response: Task
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type events = {
|
||||||
|
taskUpdate: Task,
|
||||||
|
tokenReissue: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TaskState = 'queued' | 'processing' | 'error' | 'success'
|
||||||
|
|
||||||
|
export type Task<T extends keyof tasks = keyof tasks, S extends TaskState = TaskState> = {
|
||||||
|
id: number,
|
||||||
|
type: T,
|
||||||
|
creationDate: string,
|
||||||
|
cost: string
|
||||||
|
state: S,
|
||||||
|
} & (S extends 'success'
|
||||||
|
? { result: tasks[T]['result'] }
|
||||||
|
: { result: null })
|
18
tsconfig.json
Normal file
18
tsconfig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "esnext",
|
||||||
|
"allowJs": false,
|
||||||
|
"declaration": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"strict": true,
|
||||||
|
"types": [ "node" ],
|
||||||
|
"rootDir": ".",
|
||||||
|
"incremental": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"paths": {
|
||||||
|
"%env%": ["./src/env/node"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
webpack.config.js
Normal file
67
webpack.config.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
const build = env => ({
|
||||||
|
mode: 'production',
|
||||||
|
entry: './src/index.ts',
|
||||||
|
module: {
|
||||||
|
rules: [{
|
||||||
|
test: /\.ts$/,
|
||||||
|
use: {
|
||||||
|
loader: 'ts-loader',
|
||||||
|
options: {
|
||||||
|
compilerOptions: {
|
||||||
|
module: 'esnext',
|
||||||
|
paths: {
|
||||||
|
'%env%': [`./src/env/${env}`]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
exclude: /node_modules/
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'%env%': path.resolve(__dirname, `src/env/${env}`)
|
||||||
|
},
|
||||||
|
extensions: [ '.ts', '.js' ]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = [{
|
||||||
|
// prebuilt binary, for browser usage
|
||||||
|
...build('web'),
|
||||||
|
output: {
|
||||||
|
library: {
|
||||||
|
name: 'Sati',
|
||||||
|
type: 'umd'
|
||||||
|
},
|
||||||
|
filename: `sati.web.umd.js`
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
// prebuilt binary with external dependencies, for browser usage with bundlers
|
||||||
|
...build('web'),
|
||||||
|
output: {
|
||||||
|
library: {
|
||||||
|
type: 'module'
|
||||||
|
},
|
||||||
|
filename: `sati.web.esm.js`
|
||||||
|
},
|
||||||
|
externals: /^[^\.%]/,
|
||||||
|
experiments: {
|
||||||
|
outputModule: true
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
// prebuilt node version
|
||||||
|
...build('node'),
|
||||||
|
output: {
|
||||||
|
library: {
|
||||||
|
type: 'commonjs2'
|
||||||
|
},
|
||||||
|
filename: `sati.node.cjs.js`
|
||||||
|
},
|
||||||
|
externals: /^[^\.%]/,
|
||||||
|
optimization: {
|
||||||
|
minimize: false
|
||||||
|
}
|
||||||
|
}]
|
Loading…
x
Reference in New Issue
Block a user