zaileys 0.29.7-beta → 0.29.9-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -342
- package/bun.lock +1027 -0
- package/dist/classes/Client.d.ts +17 -0
- package/dist/classes/Event.d.ts +12 -0
- package/dist/classes/Parser.d.ts +3 -0
- package/dist/database/handler.d.ts +12 -0
- package/dist/database/schema.d.ts +63 -0
- package/dist/helpers/adapter.d.ts +57 -0
- package/dist/helpers/error.d.ts +8 -0
- package/dist/index.d.ts +2 -235
- package/dist/types/adapter/general.d.ts +156 -0
- package/dist/types/classes/client.d.ts +152 -0
- package/dist/types/classes/event.d.ts +65 -0
- package/dist/zaileys.cjs.js +1 -0
- package/dist/zaileys.esm.js +1 -0
- package/package.json +42 -29
- package/rollup.config.js +38 -0
- package/src/classes/Client.ts +73 -0
- package/src/classes/Event.ts +59 -0
- package/src/classes/Parser.ts +3 -0
- package/src/database/handler.ts +272 -0
- package/src/database/schema.ts +37 -0
- package/src/helpers/adapter.ts +125 -0
- package/src/helpers/error.ts +13 -0
- package/src/index.ts +2 -0
- package/src/types/adapter/general.ts +178 -0
- package/src/types/classes/client.ts +53 -0
- package/src/types/classes/event.ts +29 -0
- package/src/types/libsignal.d.ts +4 -0
- package/test/example.ts +37 -0
- package/tsconfig.json +16 -0
- package/LICENSE +0 -21
- package/dist/index.d.mts +0 -235
- package/dist/index.js +0 -1
- package/dist/index.mjs +0 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { randomBytes, randomUUID } from "crypto";
|
|
2
|
+
import { curve as Curve } from "libsignal";
|
|
3
|
+
import { AppDataSync, Fingerprint, KeyPair, valueReplacer, valueReviver } from "../types/adapter/general";
|
|
4
|
+
|
|
5
|
+
const curve = Curve as any;
|
|
6
|
+
|
|
7
|
+
const generateKeyPair = () => {
|
|
8
|
+
const { pubKey, privKey } = curve.generateKeyPair();
|
|
9
|
+
return {
|
|
10
|
+
private: Buffer.from(privKey),
|
|
11
|
+
public: Buffer.from(pubKey.slice(1)),
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const generateSignalPubKey = (pubKey: Uint8Array) => {
|
|
16
|
+
return pubKey.length === 33 ? pubKey : Buffer.concat([Buffer.from([5]), pubKey]);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const sign = (privateKey: object, buf: Uint8Array) => {
|
|
20
|
+
return curve.calculateSignature(privateKey, buf);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const signedKeyPair = (identityKeyPair: KeyPair, keyId: number) => {
|
|
24
|
+
const preKey = generateKeyPair();
|
|
25
|
+
const pubKey = generateSignalPubKey(preKey.public);
|
|
26
|
+
const signature = sign(identityKeyPair.private, pubKey);
|
|
27
|
+
return { keyPair: preKey, signature, keyId };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const allocate = (str: string) => {
|
|
31
|
+
let p = str.length;
|
|
32
|
+
|
|
33
|
+
if (!p) {
|
|
34
|
+
return new Uint8Array(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let n = 0;
|
|
38
|
+
|
|
39
|
+
while (--p % 4 > 1 && str.charAt(p) === "=") {
|
|
40
|
+
++n;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return new Uint8Array(Math.ceil(str.length * 3) / 4 - n).fill(0);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const parseTimestamp = (timestamp: string | number | Long) => {
|
|
47
|
+
if (typeof timestamp === "string") {
|
|
48
|
+
return parseInt(timestamp, 10);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typeof timestamp === "number") {
|
|
52
|
+
return timestamp;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return timestamp;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const fromObject = (args: AppDataSync) => {
|
|
59
|
+
const f: Fingerprint = {
|
|
60
|
+
...args.fingerprint,
|
|
61
|
+
deviceIndexes: Array.isArray(args.fingerprint.deviceIndexes) ? args.fingerprint.deviceIndexes : [],
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const message = {
|
|
65
|
+
keyData: Array.isArray(args.keyData) ? args.keyData : new Uint8Array(),
|
|
66
|
+
fingerprint: {
|
|
67
|
+
rawId: f.rawId || 0,
|
|
68
|
+
currentIndex: f.rawId || 0,
|
|
69
|
+
deviceIndexes: f.deviceIndexes,
|
|
70
|
+
},
|
|
71
|
+
timestamp: parseTimestamp(args.timestamp),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
if (typeof args.keyData === "string") {
|
|
75
|
+
message.keyData = allocate(args.keyData);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return message;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const BufferJSON = {
|
|
82
|
+
replacer: (_: string, value: valueReplacer) => {
|
|
83
|
+
if (value?.type === "Buffer" && Array.isArray(value?.data)) {
|
|
84
|
+
return {
|
|
85
|
+
type: "Buffer",
|
|
86
|
+
data: Buffer.from(value?.data).toString("base64"),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return value;
|
|
90
|
+
},
|
|
91
|
+
reviver: (_: string, value: valueReviver) => {
|
|
92
|
+
if (value?.type === "Buffer") {
|
|
93
|
+
return Buffer.from(value?.data, "base64");
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const initAuthCreds = () => {
|
|
100
|
+
const identityKey = generateKeyPair();
|
|
101
|
+
return {
|
|
102
|
+
noiseKey: generateKeyPair(),
|
|
103
|
+
pairingEphemeralKeyPair: generateKeyPair(),
|
|
104
|
+
signedIdentityKey: identityKey,
|
|
105
|
+
signedPreKey: signedKeyPair(identityKey, 1),
|
|
106
|
+
registrationId: Uint16Array.from(randomBytes(2))[0] & 16383,
|
|
107
|
+
advSecretKey: randomBytes(32).toString("base64"),
|
|
108
|
+
processedHistoryMessages: [],
|
|
109
|
+
nextPreKeyId: 1,
|
|
110
|
+
firstUnuploadedPreKeyId: 1,
|
|
111
|
+
accountSyncCounter: 0,
|
|
112
|
+
accountSettings: {
|
|
113
|
+
unarchiveChats: false,
|
|
114
|
+
},
|
|
115
|
+
deviceId: Buffer.from(randomUUID().replace(/-/g, ""), "hex").toString("base64url"),
|
|
116
|
+
phoneId: randomUUID(),
|
|
117
|
+
identityId: randomBytes(20),
|
|
118
|
+
backupToken: randomBytes(20),
|
|
119
|
+
registered: false,
|
|
120
|
+
registration: {} as never,
|
|
121
|
+
pairingCode: undefined,
|
|
122
|
+
lastPropHash: undefined,
|
|
123
|
+
routingInfo: undefined,
|
|
124
|
+
};
|
|
125
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ZodError } from "zod";
|
|
2
|
+
|
|
3
|
+
export const handleZodError = (error: ZodError) => {
|
|
4
|
+
const formatted = error.errors.map((err) => ({
|
|
5
|
+
field: err.path.join("."),
|
|
6
|
+
message: err.message,
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
status: "error",
|
|
11
|
+
errors: formatted,
|
|
12
|
+
};
|
|
13
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
type Awaitable<T> = T | Promise<T>;
|
|
2
|
+
|
|
3
|
+
export type AuthAdapterHandlerType = Promise<{
|
|
4
|
+
state: AuthenticationState;
|
|
5
|
+
saveCreds: () => Promise<void>;
|
|
6
|
+
clear: () => Promise<void>;
|
|
7
|
+
removeCreds: () => Promise<void>
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
type Contact = {
|
|
11
|
+
id: string;
|
|
12
|
+
lid?: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
notify?: string;
|
|
15
|
+
verifiedName?: string;
|
|
16
|
+
imgUrl?: string | null;
|
|
17
|
+
status?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type Account = {
|
|
21
|
+
details?: Uint8Array | null;
|
|
22
|
+
accountSignatureKey?: Uint8Array | null;
|
|
23
|
+
accountSignature?: Uint8Array | null;
|
|
24
|
+
deviceSignature?: Uint8Array | null;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type SignedKeyPair = {
|
|
28
|
+
keyPair: KeyPair;
|
|
29
|
+
signature: Uint8Array;
|
|
30
|
+
keyId: number;
|
|
31
|
+
timestampS?: number;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type ProtocolAddress = {
|
|
35
|
+
name: string;
|
|
36
|
+
deviceId: number;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
type SignalIdentity = {
|
|
40
|
+
identifier: ProtocolAddress;
|
|
41
|
+
identifierKey: Uint8Array;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
type LTHashState = {
|
|
45
|
+
version: number;
|
|
46
|
+
hash: Buffer;
|
|
47
|
+
indexValueMap: {
|
|
48
|
+
[indexMacBase64: string]: { valueMac: Uint8Array | Buffer };
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type SignalCreds = {
|
|
53
|
+
readonly signedIdentityKey: KeyPair;
|
|
54
|
+
readonly signedPreKey: SignedKeyPair;
|
|
55
|
+
readonly registrationId: number;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
type AccountSettings = {
|
|
59
|
+
unarchiveChats: boolean;
|
|
60
|
+
defaultDisappearingMode?: Pick<any, "ephemeralExpiration" | "ephemeralSettingTimestamp">;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
type SignalKeyStore = {
|
|
64
|
+
get<T extends keyof SignalDataTypeMap>(
|
|
65
|
+
type: T,
|
|
66
|
+
ids: string[]
|
|
67
|
+
): Awaitable<{
|
|
68
|
+
[id: string]: SignalDataTypeMap[T];
|
|
69
|
+
}>;
|
|
70
|
+
set(data: SignalDataSet): Awaitable<void>;
|
|
71
|
+
clear?(): Awaitable<void>;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
interface RegistrationOptions {
|
|
75
|
+
phoneNumber?: string;
|
|
76
|
+
phoneNumberCountryCode: string;
|
|
77
|
+
phoneNumberNationalNumber: string;
|
|
78
|
+
phoneNumberMobileCountryCode: string;
|
|
79
|
+
phoneNumberMobileNetworkCode: string;
|
|
80
|
+
method?: "sms" | "voice" | "captcha";
|
|
81
|
+
captcha?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type SslOptions = {
|
|
85
|
+
pfx?: string;
|
|
86
|
+
key?: string | string[] | Buffer | Buffer[];
|
|
87
|
+
passphrase?: string;
|
|
88
|
+
cert?: string | string[] | Buffer | Buffer[];
|
|
89
|
+
ca?: string | string[] | Buffer | Buffer[];
|
|
90
|
+
crl?: string | string[];
|
|
91
|
+
ciphers?: string;
|
|
92
|
+
rejectUnauthorized?: boolean;
|
|
93
|
+
minVersion?: string;
|
|
94
|
+
maxVersion?: string;
|
|
95
|
+
verifyIdentity?: boolean;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export type Fingerprint = {
|
|
99
|
+
rawId: number;
|
|
100
|
+
currentIndex: number;
|
|
101
|
+
deviceIndexes: number[];
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export type AppDataSync = {
|
|
105
|
+
keyData: Uint8Array;
|
|
106
|
+
fingerprint: Fingerprint;
|
|
107
|
+
timestamp: Long | number;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export type SignalDataTypeMap = {
|
|
111
|
+
session: Uint8Array;
|
|
112
|
+
"pre-key": KeyPair;
|
|
113
|
+
"sender-key": Uint8Array;
|
|
114
|
+
"app-state-sync-key": AppDataSync;
|
|
115
|
+
"app-state-sync-version": LTHashState;
|
|
116
|
+
"sender-key-memory": {
|
|
117
|
+
[jid: string]: boolean;
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export type SignalDataSet = {
|
|
122
|
+
[T in keyof SignalDataTypeMap]?: {
|
|
123
|
+
[id: string]: SignalDataTypeMap[T] | null;
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export type KeyPair = {
|
|
128
|
+
public: Uint8Array;
|
|
129
|
+
private: Uint8Array;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export type sqlData = {
|
|
133
|
+
constructor: {
|
|
134
|
+
name: "RowDataPacket";
|
|
135
|
+
};
|
|
136
|
+
value?: object[];
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export type valueReplacer = {
|
|
140
|
+
data: number[];
|
|
141
|
+
type: string;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export type valueReviver = {
|
|
145
|
+
data: string;
|
|
146
|
+
type: string;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export type AuthenticationState = {
|
|
150
|
+
creds: AuthenticationCreds;
|
|
151
|
+
keys: SignalKeyStore;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export type AuthenticationCreds = SignalCreds & {
|
|
155
|
+
readonly noiseKey: KeyPair;
|
|
156
|
+
readonly pairingEphemeralKeyPair: KeyPair;
|
|
157
|
+
advSecretKey: string;
|
|
158
|
+
me?: Contact;
|
|
159
|
+
account?: Account;
|
|
160
|
+
signalIdentities?: SignalIdentity[];
|
|
161
|
+
myAppStateKeyId?: string;
|
|
162
|
+
firstUnuploadedPreKeyId: number;
|
|
163
|
+
nextPreKeyId: number;
|
|
164
|
+
lastAccountSyncTimestamp?: number;
|
|
165
|
+
platform?: string;
|
|
166
|
+
processedHistoryMessages: Pick<any, "key" | "messageTimestamp">[];
|
|
167
|
+
accountSyncCounter: number;
|
|
168
|
+
accountSettings: AccountSettings;
|
|
169
|
+
deviceId: string;
|
|
170
|
+
phoneId: string;
|
|
171
|
+
identityId: Buffer;
|
|
172
|
+
registered: boolean;
|
|
173
|
+
backupToken: Buffer;
|
|
174
|
+
registration: RegistrationOptions;
|
|
175
|
+
pairingCode: string | undefined;
|
|
176
|
+
lastPropHash: string | undefined;
|
|
177
|
+
routingInfo: Buffer | undefined;
|
|
178
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const AdapterDatabaseType = z
|
|
4
|
+
.object({
|
|
5
|
+
type: z.enum(["sqlite", "postgresql", "mysql"]).default("sqlite"),
|
|
6
|
+
connection: z
|
|
7
|
+
.object({
|
|
8
|
+
url: z.string().default("./zaileys.db"),
|
|
9
|
+
})
|
|
10
|
+
.optional()
|
|
11
|
+
.default({}),
|
|
12
|
+
})
|
|
13
|
+
.optional()
|
|
14
|
+
.default({});
|
|
15
|
+
|
|
16
|
+
const ClientClassesBaseType = {
|
|
17
|
+
prefix: z.string().optional(),
|
|
18
|
+
ignoreMe: z.boolean().optional().default(true),
|
|
19
|
+
showLogs: z.boolean().optional().default(true),
|
|
20
|
+
autoMentions: z.boolean().optional().default(true),
|
|
21
|
+
autoOnline: z.boolean().optional().default(true),
|
|
22
|
+
autoRead: z.boolean().optional().default(true),
|
|
23
|
+
autoRejectCall: z.boolean().optional().default(true),
|
|
24
|
+
database: AdapterDatabaseType,
|
|
25
|
+
citation: z
|
|
26
|
+
.record(z.function().returns(z.union([z.number().array(), z.promise(z.number().array())])))
|
|
27
|
+
.optional()
|
|
28
|
+
.transform(async (citation) => {
|
|
29
|
+
const transform: Record<string, any> = {};
|
|
30
|
+
if (citation) {
|
|
31
|
+
for (const key of Object.keys(citation)) {
|
|
32
|
+
const news = `is${key.charAt(0).toUpperCase() + key.slice(1)}`;
|
|
33
|
+
const result = await citation[key]();
|
|
34
|
+
transform[news] = result;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return transform;
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const ClientPairingType = z.object({
|
|
42
|
+
authType: z.literal("pairing"),
|
|
43
|
+
phoneNumber: z.number(),
|
|
44
|
+
...ClientClassesBaseType,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const ClientQRType = z.object({
|
|
48
|
+
authType: z.literal("qr"),
|
|
49
|
+
phoneNumber: z.undefined().optional(),
|
|
50
|
+
...ClientClassesBaseType,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export const ClientClassesType = z.discriminatedUnion("authType", [ClientPairingType, ClientQRType]);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
const EventConnectionType = z.object({
|
|
4
|
+
status: z.enum(["connecting", "open", "close"]),
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
const EventMessagesType = z.object({
|
|
8
|
+
messages: z.object({
|
|
9
|
+
remoteJid: z.string(),
|
|
10
|
+
id: z.string(),
|
|
11
|
+
}),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const EventCallType = z.object({
|
|
15
|
+
call: z.object({
|
|
16
|
+
id: z.string(),
|
|
17
|
+
from: z.string(),
|
|
18
|
+
timestamp: z.number(),
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const EventEnumType = z.enum(["connection", "messages", "call"]);
|
|
23
|
+
export type EventEnumType = z.infer<typeof EventEnumType>;
|
|
24
|
+
|
|
25
|
+
export type EventCallbackType = {
|
|
26
|
+
connection: (data: z.infer<typeof EventConnectionType>) => void;
|
|
27
|
+
messages: (data: z.infer<typeof EventMessagesType>) => void;
|
|
28
|
+
call: (data: z.infer<typeof EventCallType>) => void;
|
|
29
|
+
};
|
package/test/example.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Client from "../src";
|
|
2
|
+
|
|
3
|
+
// the configuration below is the default
|
|
4
|
+
const wa = new Client({
|
|
5
|
+
prefix: "/", // for command message, example '/'
|
|
6
|
+
phoneNumber: 6287833764462, // fill bot phone number if auth type is 'pairing'
|
|
7
|
+
authType: "pairing", // auth type 'pairing' or 'qr'
|
|
8
|
+
ignoreMe: true, // ignore messages from bot (bot phone number)
|
|
9
|
+
showLogs: true, // show logs of any chats
|
|
10
|
+
autoMentions: true, // bot will be auto mentioned if text contains sender number with '@' prefix
|
|
11
|
+
autoOnline: true, // bot status will be mark online
|
|
12
|
+
autoRead: true, // auto read message from any chats
|
|
13
|
+
autoRejectCall: true, // auto reject call if someone call you
|
|
14
|
+
database: {
|
|
15
|
+
type: "sqlite", // database type "sqlite" | "postgresql" | "mysql"
|
|
16
|
+
connection: {
|
|
17
|
+
url: "./db/zaileys.db", // database url
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
citation: {
|
|
21
|
+
author: async () => {
|
|
22
|
+
// const res = await fetch...
|
|
23
|
+
return await [6285136635787];
|
|
24
|
+
},
|
|
25
|
+
myGroup: () => [6285136635787],
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
wa.on("connection", (ctx) => {
|
|
30
|
+
// console.log("🚀 ~ example.ts:30 ~ wa.on ~ ctx:", ctx);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
wa.on("messages", (ctx) => {
|
|
34
|
+
console.log("🚀 ~ example.ts:31 ~ wa.on ~ ctx:", ctx);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
wa.on("call", () => {});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2019",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationDir": "dist",
|
|
8
|
+
"emitDeclarationOnly": false,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"strict": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"sourceMap": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src"]
|
|
16
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Zeative Media
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|