pg-boss 12.4.0 → 12.5.0
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/dist/attorney.d.ts +19 -0
- package/dist/attorney.d.ts.map +1 -0
- package/dist/attorney.js +170 -0
- package/dist/boss.d.ts +16 -0
- package/dist/boss.d.ts.map +1 -0
- package/dist/boss.js +135 -0
- package/dist/contractor.d.ts +22 -0
- package/dist/contractor.d.ts.map +1 -0
- package/dist/contractor.js +81 -0
- package/dist/db.d.ts +16 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +46 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +239 -0
- package/dist/manager.d.ts +89 -0
- package/dist/manager.d.ts.map +1 -0
- package/dist/manager.js +547 -0
- package/dist/migrationStore.d.ts +7 -0
- package/dist/migrationStore.d.ts.map +1 -0
- package/dist/migrationStore.js +126 -0
- package/dist/plans.d.ts +78 -0
- package/dist/plans.d.ts.map +1 -0
- package/dist/plans.js +885 -0
- package/dist/spy.d.ts +23 -0
- package/dist/spy.d.ts.map +1 -0
- package/dist/spy.js +73 -0
- package/dist/timekeeper.d.ts +34 -0
- package/dist/timekeeper.d.ts.map +1 -0
- package/dist/timekeeper.js +158 -0
- package/dist/tools.d.ts +18 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +45 -0
- package/dist/types.d.ts +230 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/worker.d.ts +41 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +107 -0
- package/package.json +8 -11
- package/dist/index.d.mts +0 -285
- package/dist/index.mjs +0 -2468
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as types from './types.ts';
|
|
2
|
+
declare const POLICY: {
|
|
3
|
+
MAX_EXPIRATION_HOURS: number;
|
|
4
|
+
MIN_POLLING_INTERVAL_MS: number;
|
|
5
|
+
MAX_RETENTION_DAYS: number;
|
|
6
|
+
};
|
|
7
|
+
declare function validateQueueArgs(config?: any): void;
|
|
8
|
+
declare function checkSendArgs(args: any): types.Request;
|
|
9
|
+
declare function checkWorkArgs(name: string, args: any[]): {
|
|
10
|
+
options: types.ResolvedWorkOptions;
|
|
11
|
+
callback: types.WorkHandler<any>;
|
|
12
|
+
};
|
|
13
|
+
declare function checkFetchArgs(name: string, options: any): void;
|
|
14
|
+
declare function getConfig(value: string | types.ConstructorOptions): types.ResolvedConstructorOptions;
|
|
15
|
+
declare function assertPostgresObjectName(name: string): void;
|
|
16
|
+
declare function assertQueueName(name: string): void;
|
|
17
|
+
declare function assertKey(key: string): void;
|
|
18
|
+
export { assertKey, assertPostgresObjectName, assertQueueName, checkFetchArgs, checkSendArgs, checkWorkArgs, getConfig, POLICY, validateQueueArgs };
|
|
19
|
+
//# sourceMappingURL=attorney.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attorney.d.ts","sourceRoot":"","sources":["../src/attorney.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAExC,QAAA,MAAM,MAAM;;;;CAIX,CAAA;AAMD,iBAAS,iBAAiB,CAAE,MAAM,GAAE,GAAQ,QAW3C;AAED,iBAAS,aAAa,CAAE,IAAI,EAAE,GAAG,GAAG,KAAK,CAAC,OAAO,CA8ChD;AAED,iBAAS,aAAa,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG;IAClD,OAAO,EAAE,KAAK,CAAC,mBAAmB,CAAA;IAClC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;CACjC,CAyBA;AAED,iBAAS,cAAc,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAOlD;AAED,iBAAS,SAAS,CAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC,0BAA0B,CAmB9F;AAkBD,iBAAS,wBAAwB,CAAE,IAAI,EAAE,MAAM,QAK9C;AAED,iBAAS,eAAe,CAAE,IAAI,EAAE,MAAM,QAIrC;AAED,iBAAS,SAAS,CAAE,GAAG,EAAE,MAAM,QAI9B;AAuFD,OAAO,EACL,SAAS,EACT,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,aAAa,EACb,aAAa,EACb,SAAS,EACT,MAAM,EACN,iBAAiB,EAClB,CAAA"}
|
package/dist/attorney.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { DEFAULT_SCHEMA } from "./plans.js";
|
|
3
|
+
const POLICY = {
|
|
4
|
+
MAX_EXPIRATION_HOURS: 24,
|
|
5
|
+
MIN_POLLING_INTERVAL_MS: 500,
|
|
6
|
+
MAX_RETENTION_DAYS: 365
|
|
7
|
+
};
|
|
8
|
+
function assertObjectName(value, name = 'Name') {
|
|
9
|
+
assert(/^[\w.-]+$/.test(value), `${name} can only contain alphanumeric characters, underscores, hyphens, or periods`);
|
|
10
|
+
}
|
|
11
|
+
function validateQueueArgs(config = {}) {
|
|
12
|
+
assert(!('deadLetter' in config) || config.deadLetter === null || (typeof config.deadLetter === 'string'), 'deadLetter must be a string');
|
|
13
|
+
if (config.deadLetter) {
|
|
14
|
+
assertObjectName(config.deadLetter, 'deadLetter');
|
|
15
|
+
}
|
|
16
|
+
validateRetryConfig(config);
|
|
17
|
+
validateExpirationConfig(config);
|
|
18
|
+
validateRetentionConfig(config);
|
|
19
|
+
validateDeletionConfig(config);
|
|
20
|
+
}
|
|
21
|
+
function checkSendArgs(args) {
|
|
22
|
+
let name, data, options;
|
|
23
|
+
if (typeof args[0] === 'string') {
|
|
24
|
+
name = args[0];
|
|
25
|
+
data = args[1];
|
|
26
|
+
assert(typeof data !== 'function', 'send() cannot accept a function as the payload. Did you intend to use work()?');
|
|
27
|
+
options = args[2];
|
|
28
|
+
}
|
|
29
|
+
else if (typeof args[0] === 'object') {
|
|
30
|
+
assert(args.length === 1, 'send object API only accepts 1 argument');
|
|
31
|
+
const job = args[0];
|
|
32
|
+
assert(job, 'boss requires all jobs to have a name');
|
|
33
|
+
name = job.name;
|
|
34
|
+
data = job.data;
|
|
35
|
+
options = job.options;
|
|
36
|
+
}
|
|
37
|
+
options = options || {};
|
|
38
|
+
assert(name, 'boss requires all jobs to have a queue name');
|
|
39
|
+
assert(typeof options === 'object', 'options should be an object');
|
|
40
|
+
options = { ...options };
|
|
41
|
+
assert(!('priority' in options) || (Number.isInteger(options.priority)), 'priority must be an integer');
|
|
42
|
+
options.priority = options.priority || 0;
|
|
43
|
+
options.startAfter = (options.startAfter instanceof Date && typeof options.startAfter.toISOString === 'function')
|
|
44
|
+
? options.startAfter.toISOString()
|
|
45
|
+
: (+options.startAfter > 0)
|
|
46
|
+
? '' + options.startAfter
|
|
47
|
+
: (typeof options.startAfter === 'string')
|
|
48
|
+
? options.startAfter
|
|
49
|
+
: undefined;
|
|
50
|
+
validateRetryConfig(options);
|
|
51
|
+
validateExpirationConfig(options);
|
|
52
|
+
validateRetentionConfig(options);
|
|
53
|
+
validateDeletionConfig(options);
|
|
54
|
+
return { name, data, options };
|
|
55
|
+
}
|
|
56
|
+
function checkWorkArgs(name, args) {
|
|
57
|
+
let options, callback;
|
|
58
|
+
assert(name, 'queue name is required');
|
|
59
|
+
if (args.length === 1) {
|
|
60
|
+
callback = args[0];
|
|
61
|
+
options = {};
|
|
62
|
+
}
|
|
63
|
+
else if (args.length > 1) {
|
|
64
|
+
options = args[0] || {};
|
|
65
|
+
callback = args[1];
|
|
66
|
+
}
|
|
67
|
+
assert(typeof callback === 'function', 'expected callback to be a function');
|
|
68
|
+
assert(typeof options === 'object', 'expected config to be an object');
|
|
69
|
+
options = { ...options };
|
|
70
|
+
applyPollingInterval(options);
|
|
71
|
+
assert(!('batchSize' in options) || (Number.isInteger(options.batchSize) && options.batchSize >= 1), 'batchSize must be an integer > 0');
|
|
72
|
+
assert(!('includeMetadata' in options) || typeof options.includeMetadata === 'boolean', 'includeMetadata must be a boolean');
|
|
73
|
+
assert(!('priority' in options) || typeof options.priority === 'boolean', 'priority must be a boolean');
|
|
74
|
+
return { options, callback };
|
|
75
|
+
}
|
|
76
|
+
function checkFetchArgs(name, options) {
|
|
77
|
+
assert(name, 'missing queue name');
|
|
78
|
+
assert(!('batchSize' in options) || (Number.isInteger(options.batchSize) && options.batchSize >= 1), 'batchSize must be an integer > 0');
|
|
79
|
+
assert(!('includeMetadata' in options) || typeof options.includeMetadata === 'boolean', 'includeMetadata must be a boolean');
|
|
80
|
+
assert(!('priority' in options) || typeof options.priority === 'boolean', 'priority must be a boolean');
|
|
81
|
+
assert(!('ignoreStartAfter' in options) || typeof options.ignoreStartAfter === 'boolean', 'ignoreStartAfter must be a boolean');
|
|
82
|
+
}
|
|
83
|
+
function getConfig(value) {
|
|
84
|
+
assert(value && (typeof value === 'object' || typeof value === 'string'), 'configuration assert: string or config object is required to connect to postgres');
|
|
85
|
+
const config = (typeof value === 'string')
|
|
86
|
+
? { connectionString: value }
|
|
87
|
+
: { ...value };
|
|
88
|
+
config.schedule = ('schedule' in config) ? config.schedule : true;
|
|
89
|
+
config.supervise = ('supervise' in config) ? config.supervise : true;
|
|
90
|
+
config.migrate = ('migrate' in config) ? config.migrate : true;
|
|
91
|
+
config.createSchema = ('createSchema' in config) ? config.createSchema : true;
|
|
92
|
+
applySchemaConfig(config);
|
|
93
|
+
applyOpsConfig(config);
|
|
94
|
+
applyScheduleConfig(config);
|
|
95
|
+
validateWarningConfig(config);
|
|
96
|
+
return config;
|
|
97
|
+
}
|
|
98
|
+
function applySchemaConfig(config) {
|
|
99
|
+
if (config.schema) {
|
|
100
|
+
assertPostgresObjectName(config.schema);
|
|
101
|
+
}
|
|
102
|
+
config.schema = config.schema || DEFAULT_SCHEMA;
|
|
103
|
+
}
|
|
104
|
+
function validateWarningConfig(config) {
|
|
105
|
+
assert(!('warningQueueSize' in config) || config.warningQueueSize >= 1, 'configuration assert: warningQueueSize must be at least 1');
|
|
106
|
+
assert(!('warningSlowQuerySeconds' in config) || config.warningSlowQuerySeconds >= 1, 'configuration assert: warningSlowQuerySeconds must be at least 1');
|
|
107
|
+
}
|
|
108
|
+
function assertPostgresObjectName(name) {
|
|
109
|
+
assert(typeof name === 'string', 'Name must be a string');
|
|
110
|
+
assert(name.length <= 50, 'Name cannot exceed 50 characters');
|
|
111
|
+
assert(!/\W/.test(name), 'Name can only contain alphanumeric characters or underscores');
|
|
112
|
+
assert(!/^\d/.test(name), 'Name cannot start with a number');
|
|
113
|
+
}
|
|
114
|
+
function assertQueueName(name) {
|
|
115
|
+
assert(name, 'Name is required');
|
|
116
|
+
assert(typeof name === 'string', 'Name must be a string');
|
|
117
|
+
assertObjectName(name);
|
|
118
|
+
}
|
|
119
|
+
function assertKey(key) {
|
|
120
|
+
if (!key)
|
|
121
|
+
return;
|
|
122
|
+
assert(typeof key === 'string', 'Key must be a string');
|
|
123
|
+
assertObjectName(key, 'Key');
|
|
124
|
+
}
|
|
125
|
+
function validateRetentionConfig(config) {
|
|
126
|
+
assert(!('retentionSeconds' in config) || config.retentionSeconds >= 1, 'configuration assert: retentionSeconds must be at least every second');
|
|
127
|
+
}
|
|
128
|
+
function validateExpirationConfig(config) {
|
|
129
|
+
assert(!('expireInSeconds' in config) || config.expireInSeconds >= 1, 'configuration assert: expireInSeconds must be at least every second');
|
|
130
|
+
assert(!config.expireInSeconds || config.expireInSeconds / 60 / 60 < POLICY.MAX_EXPIRATION_HOURS, `configuration assert: expiration cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`);
|
|
131
|
+
}
|
|
132
|
+
function validateRetryConfig(config) {
|
|
133
|
+
assert(!('retryDelay' in config) || (Number.isInteger(config.retryDelay) && config.retryDelay >= 0), 'retryDelay must be an integer >= 0');
|
|
134
|
+
assert(!('retryLimit' in config) || (Number.isInteger(config.retryLimit) && config.retryLimit >= 0), 'retryLimit must be an integer >= 0');
|
|
135
|
+
assert(!('retryBackoff' in config) || (config.retryBackoff === true || config.retryBackoff === false), 'retryBackoff must be either true or false');
|
|
136
|
+
assert(!('retryDelayMax' in config) || config.retryDelayMax === null || config.retryBackoff === true, 'retryDelayMax can only be set if retryBackoff is true');
|
|
137
|
+
assert(!('retryDelayMax' in config) || config.retryDelayMax === null || (Number.isInteger(config.retryDelayMax) && config.retryDelayMax >= 0), 'retryDelayMax must be an integer >= 0');
|
|
138
|
+
}
|
|
139
|
+
function applyPollingInterval(config) {
|
|
140
|
+
assert(!('pollingIntervalSeconds' in config) || config.pollingIntervalSeconds >= POLICY.MIN_POLLING_INTERVAL_MS / 1000, `configuration assert: pollingIntervalSeconds must be at least every ${POLICY.MIN_POLLING_INTERVAL_MS}ms`);
|
|
141
|
+
config.pollingInterval = ('pollingIntervalSeconds' in config)
|
|
142
|
+
? config.pollingIntervalSeconds * 1000
|
|
143
|
+
: 2000;
|
|
144
|
+
}
|
|
145
|
+
function applyOpsConfig(config) {
|
|
146
|
+
assert(!('superviseIntervalSeconds' in config) || config.superviseIntervalSeconds >= 1, 'configuration assert: superviseIntervalSeconds must be at least every second');
|
|
147
|
+
config.superviseIntervalSeconds = config.superviseIntervalSeconds || 60;
|
|
148
|
+
assert(config.superviseIntervalSeconds / 60 / 60 <= POLICY.MAX_EXPIRATION_HOURS, `configuration assert: superviseIntervalSeconds cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`);
|
|
149
|
+
assert(!('maintenanceIntervalSeconds' in config) || config.maintenanceIntervalSeconds >= 1, 'configuration assert: maintenanceIntervalSeconds must be at least every second');
|
|
150
|
+
config.maintenanceIntervalSeconds = config.maintenanceIntervalSeconds || POLICY.MAX_EXPIRATION_HOURS * 60 * 60;
|
|
151
|
+
assert(config.maintenanceIntervalSeconds / 60 / 60 <= POLICY.MAX_EXPIRATION_HOURS, `configuration assert: maintenanceIntervalSeconds cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`);
|
|
152
|
+
assert(!('monitorIntervalSeconds' in config) || config.monitorIntervalSeconds >= 1, 'configuration assert: monitorIntervalSeconds must be at least every second');
|
|
153
|
+
config.monitorIntervalSeconds = config.monitorIntervalSeconds || 60;
|
|
154
|
+
assert(config.monitorIntervalSeconds / 60 / 60 <= POLICY.MAX_EXPIRATION_HOURS, `configuration assert: monitorIntervalSeconds cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`);
|
|
155
|
+
assert(!('queueCacheIntervalSeconds' in config) || config.queueCacheIntervalSeconds >= 1, 'configuration assert: queueCacheIntervalSeconds must be at least every second');
|
|
156
|
+
config.queueCacheIntervalSeconds = config.queueCacheIntervalSeconds || 60;
|
|
157
|
+
assert(config.queueCacheIntervalSeconds / 60 / 60 <= POLICY.MAX_EXPIRATION_HOURS, `configuration assert: queueCacheIntervalSeconds cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`);
|
|
158
|
+
}
|
|
159
|
+
function validateDeletionConfig(config) {
|
|
160
|
+
assert(!('deleteAfterSeconds' in config) || config.deleteAfterSeconds >= 1, 'configuration assert: deleteAfterSeconds must be at least every second');
|
|
161
|
+
}
|
|
162
|
+
function applyScheduleConfig(config) {
|
|
163
|
+
assert(!('clockMonitorIntervalSeconds' in config) || (config.clockMonitorIntervalSeconds >= 1 && config.clockMonitorIntervalSeconds <= 600), 'configuration assert: clockMonitorIntervalSeconds must be between 1 second and 10 minutes');
|
|
164
|
+
config.clockMonitorIntervalSeconds = config.clockMonitorIntervalSeconds || 600;
|
|
165
|
+
assert(!('cronMonitorIntervalSeconds' in config) || (config.cronMonitorIntervalSeconds >= 1 && config.cronMonitorIntervalSeconds <= 45), 'configuration assert: cronMonitorIntervalSeconds must be between 1 and 45 seconds');
|
|
166
|
+
config.cronMonitorIntervalSeconds = config.cronMonitorIntervalSeconds || 30;
|
|
167
|
+
assert(!('cronWorkerIntervalSeconds' in config) || (config.cronWorkerIntervalSeconds >= 1 && config.cronWorkerIntervalSeconds <= 45), 'configuration assert: cronWorkerIntervalSeconds must be between 1 and 45 seconds');
|
|
168
|
+
config.cronWorkerIntervalSeconds = config.cronWorkerIntervalSeconds || 5;
|
|
169
|
+
}
|
|
170
|
+
export { assertKey, assertPostgresObjectName, assertQueueName, checkFetchArgs, checkSendArgs, checkWorkArgs, getConfig, POLICY, validateQueueArgs };
|
package/dist/boss.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import EventEmitter from 'node:events';
|
|
2
|
+
import type Manager from './manager.js';
|
|
3
|
+
import * as types from './types.js';
|
|
4
|
+
declare class Boss extends EventEmitter implements types.EventsMixin {
|
|
5
|
+
#private;
|
|
6
|
+
events: {
|
|
7
|
+
error: string;
|
|
8
|
+
warning: string;
|
|
9
|
+
};
|
|
10
|
+
constructor(db: types.IDatabase, manager: Manager, config: types.ResolvedConstructorOptions);
|
|
11
|
+
start(): Promise<void>;
|
|
12
|
+
stop(): Promise<void>;
|
|
13
|
+
supervise(value?: string | types.QueueResult): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export default Boss;
|
|
16
|
+
//# sourceMappingURL=boss.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boss.d.ts","sourceRoot":"","sources":["../src/boss.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,aAAa,CAAA;AACtC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAGvC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAYnC,cAAM,IAAK,SAAQ,YAAa,YAAW,KAAK,CAAC,WAAW;;IAQ1D,MAAM;;;MAAS;gBAGb,EAAE,EAAE,KAAK,CAAC,SAAS,EACnB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,KAAK,CAAC,0BAA0B;IAkBpC,KAAK;IAUL,IAAI;IAiDJ,SAAS,CAAE,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,WAAW;CAwEpD;AAED,eAAe,IAAI,CAAA"}
|
package/dist/boss.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import EventEmitter from 'node:events';
|
|
2
|
+
import * as plans from './plans.js';
|
|
3
|
+
import { unwrapSQLResult } from './tools.js';
|
|
4
|
+
import * as types from './types.js';
|
|
5
|
+
const events = {
|
|
6
|
+
error: 'error',
|
|
7
|
+
warning: 'warning'
|
|
8
|
+
};
|
|
9
|
+
const WARNINGS = {
|
|
10
|
+
SLOW_QUERY: { seconds: 30, message: 'Warning: slow query. Your queues and/or database server should be reviewed' },
|
|
11
|
+
LARGE_QUEUE: { size: 10_000, message: 'Warning: large queue backlog. Your queue should be reviewed' }
|
|
12
|
+
};
|
|
13
|
+
class Boss extends EventEmitter {
|
|
14
|
+
#stopped;
|
|
15
|
+
#maintaining;
|
|
16
|
+
#superviseInterval;
|
|
17
|
+
#db;
|
|
18
|
+
#config;
|
|
19
|
+
#manager;
|
|
20
|
+
events = events;
|
|
21
|
+
constructor(db, manager, config) {
|
|
22
|
+
super();
|
|
23
|
+
this.#db = db;
|
|
24
|
+
this.#config = config;
|
|
25
|
+
this.#manager = manager;
|
|
26
|
+
this.#stopped = true;
|
|
27
|
+
if (config.warningSlowQuerySeconds) {
|
|
28
|
+
WARNINGS.SLOW_QUERY.seconds = config.warningSlowQuerySeconds;
|
|
29
|
+
}
|
|
30
|
+
if (config.warningQueueSize) {
|
|
31
|
+
WARNINGS.LARGE_QUEUE.size = config.warningQueueSize;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async start() {
|
|
35
|
+
if (this.#stopped) {
|
|
36
|
+
this.#superviseInterval = setInterval(() => this.#onSupervise(), this.#config.superviseIntervalSeconds * 1000);
|
|
37
|
+
this.#stopped = false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async stop() {
|
|
41
|
+
if (!this.#stopped) {
|
|
42
|
+
if (this.#superviseInterval)
|
|
43
|
+
clearInterval(this.#superviseInterval);
|
|
44
|
+
this.#stopped = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async #executeSql(sql, values) {
|
|
48
|
+
const started = Date.now();
|
|
49
|
+
const result = unwrapSQLResult(await this.#db.executeSql(sql, values));
|
|
50
|
+
const ended = Date.now();
|
|
51
|
+
const elapsed = (ended - started) / 1000;
|
|
52
|
+
if (elapsed > WARNINGS.SLOW_QUERY.seconds ||
|
|
53
|
+
this.#config.__test__warn_slow_query) {
|
|
54
|
+
this.emit(events.warning, {
|
|
55
|
+
message: WARNINGS.SLOW_QUERY.message,
|
|
56
|
+
data: { elapsed, sql, values },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
async #onSupervise() {
|
|
62
|
+
try {
|
|
63
|
+
if (this.#stopped)
|
|
64
|
+
return;
|
|
65
|
+
if (this.#maintaining)
|
|
66
|
+
return;
|
|
67
|
+
if (this.#config.__test__throw_maint) {
|
|
68
|
+
throw new Error(this.#config.__test__throw_maint);
|
|
69
|
+
}
|
|
70
|
+
this.#maintaining = true;
|
|
71
|
+
const queues = await this.#manager.getQueues();
|
|
72
|
+
for (const queue of queues) {
|
|
73
|
+
!this.#stopped && (await this.supervise(queue));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
this.emit(events.error, err);
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
this.#maintaining = false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async supervise(value) {
|
|
84
|
+
let queues;
|
|
85
|
+
if (typeof value === 'object') {
|
|
86
|
+
queues = [value];
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
queues = await this.#manager.getQueues(value);
|
|
90
|
+
}
|
|
91
|
+
const queueGroups = queues.reduce((acc, q) => {
|
|
92
|
+
const { table } = q;
|
|
93
|
+
acc[table] = acc[table] || { table, queues: [] };
|
|
94
|
+
acc[table].queues.push(q);
|
|
95
|
+
return acc;
|
|
96
|
+
}, {});
|
|
97
|
+
for (const queueGroup of Object.values(queueGroups)) {
|
|
98
|
+
const { table, queues } = queueGroup;
|
|
99
|
+
const names = queues.map((i) => i.name);
|
|
100
|
+
while (names.length) {
|
|
101
|
+
const chunk = names.splice(0, 100);
|
|
102
|
+
await this.#monitor(table, chunk);
|
|
103
|
+
await this.#maintain(table, chunk);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async #monitor(table, names) {
|
|
108
|
+
const command = plans.trySetQueueMonitorTime(this.#config.schema, names, this.#config.monitorIntervalSeconds);
|
|
109
|
+
const { rows } = await this.#executeSql(command);
|
|
110
|
+
if (rows.length) {
|
|
111
|
+
const queues = rows.map((q) => q.name);
|
|
112
|
+
const cacheStatsSql = plans.cacheQueueStats(this.#config.schema, table, queues);
|
|
113
|
+
const { rows: rowsCacheStats } = await this.#executeSql(cacheStatsSql);
|
|
114
|
+
const warnings = rowsCacheStats.filter(i => i.queuedCount > (i.warningQueueSize || WARNINGS.LARGE_QUEUE.size));
|
|
115
|
+
for (const warning of warnings) {
|
|
116
|
+
this.emit(events.warning, {
|
|
117
|
+
message: WARNINGS.LARGE_QUEUE.message,
|
|
118
|
+
data: warning,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
const sql = plans.failJobsByTimeout(this.#config.schema, table, queues);
|
|
122
|
+
await this.#executeSql(sql);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async #maintain(table, names) {
|
|
126
|
+
const command = plans.trySetQueueDeletionTime(this.#config.schema, names, this.#config.maintenanceIntervalSeconds);
|
|
127
|
+
const { rows } = await this.#executeSql(command);
|
|
128
|
+
if (rows.length) {
|
|
129
|
+
const queues = rows.map((q) => q.name);
|
|
130
|
+
const sql = plans.deletion(this.#config.schema, table, queues);
|
|
131
|
+
await this.#executeSql(sql);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export default Boss;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type * as types from './types.ts';
|
|
2
|
+
declare class Contractor {
|
|
3
|
+
static constructionPlans(schema?: string, options?: {
|
|
4
|
+
createSchema: boolean;
|
|
5
|
+
}): string;
|
|
6
|
+
static migrationPlans(schema?: string, version?: number): string;
|
|
7
|
+
static rollbackPlans(schema?: string, version?: number): string;
|
|
8
|
+
private config;
|
|
9
|
+
private db;
|
|
10
|
+
private migrations;
|
|
11
|
+
constructor(db: types.IDatabase, config: types.ResolvedConstructorOptions);
|
|
12
|
+
schemaVersion(): Promise<number | null>;
|
|
13
|
+
isInstalled(): Promise<boolean>;
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
check(): Promise<void>;
|
|
16
|
+
create(): Promise<void>;
|
|
17
|
+
migrate(version: number): Promise<void>;
|
|
18
|
+
next(version: number): Promise<void>;
|
|
19
|
+
rollback(version: number): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export default Contractor;
|
|
22
|
+
//# sourceMappingURL=contractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contractor.d.ts","sourceRoot":"","sources":["../src/contractor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAIxC,cAAM,UAAU;IACd,MAAM,CAAC,iBAAiB,CAAE,MAAM,SAAuB,EAAE,OAAO;;KAAyB;IAIzF,MAAM,CAAC,cAAc,CAAE,MAAM,SAAuB,EAAE,OAAO,SAAoB;IAIjF,MAAM,CAAC,aAAa,CAAE,MAAM,SAAuB,EAAE,OAAO,SAAgB;IAI5E,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,UAAU,CAAmB;gBAExB,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,0BAA0B;IAMpE,aAAa;IAKb,WAAW;IAKX,KAAK;IAcL,KAAK;IAcL,MAAM;IASN,OAAO,CAAE,OAAO,EAAE,MAAM;IASxB,IAAI,CAAE,OAAO,EAAE,MAAM;IAKrB,QAAQ,CAAE,OAAO,EAAE,MAAM;CAIhC;AAED,eAAe,UAAU,CAAA"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import * as plans from "./plans.js";
|
|
3
|
+
import * as migrationStore from "./migrationStore.js";
|
|
4
|
+
import packageJson from '../package.json' with { type: 'json' };
|
|
5
|
+
const schemaVersion = packageJson.pgboss.schema;
|
|
6
|
+
class Contractor {
|
|
7
|
+
static constructionPlans(schema = plans.DEFAULT_SCHEMA, options = { createSchema: true }) {
|
|
8
|
+
return plans.create(schema, schemaVersion, options);
|
|
9
|
+
}
|
|
10
|
+
static migrationPlans(schema = plans.DEFAULT_SCHEMA, version = schemaVersion - 1) {
|
|
11
|
+
return migrationStore.migrate(schema, version);
|
|
12
|
+
}
|
|
13
|
+
static rollbackPlans(schema = plans.DEFAULT_SCHEMA, version = schemaVersion) {
|
|
14
|
+
return migrationStore.rollback(schema, version);
|
|
15
|
+
}
|
|
16
|
+
config;
|
|
17
|
+
db;
|
|
18
|
+
migrations;
|
|
19
|
+
constructor(db, config) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
this.db = db;
|
|
22
|
+
this.migrations = this.config.migrations || migrationStore.getAll(this.config.schema);
|
|
23
|
+
}
|
|
24
|
+
async schemaVersion() {
|
|
25
|
+
const result = await this.db.executeSql(plans.getVersion(this.config.schema));
|
|
26
|
+
return result.rows.length ? parseInt(result.rows[0].version) : null;
|
|
27
|
+
}
|
|
28
|
+
async isInstalled() {
|
|
29
|
+
const result = await this.db.executeSql(plans.versionTableExists(this.config.schema));
|
|
30
|
+
return !!result.rows[0].name;
|
|
31
|
+
}
|
|
32
|
+
async start() {
|
|
33
|
+
const installed = await this.isInstalled();
|
|
34
|
+
if (installed) {
|
|
35
|
+
const version = await this.schemaVersion();
|
|
36
|
+
if (version !== null && schemaVersion > version) {
|
|
37
|
+
await this.migrate(version);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
await this.create();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async check() {
|
|
45
|
+
const installed = await this.isInstalled();
|
|
46
|
+
if (!installed) {
|
|
47
|
+
throw new Error('pg-boss is not installed');
|
|
48
|
+
}
|
|
49
|
+
const version = await this.schemaVersion();
|
|
50
|
+
if (schemaVersion !== version) {
|
|
51
|
+
throw new Error('pg-boss database requires migrations');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async create() {
|
|
55
|
+
try {
|
|
56
|
+
const commands = plans.create(this.config.schema, schemaVersion, this.config);
|
|
57
|
+
await this.db.executeSql(commands);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
assert(err.message.includes(plans.CREATE_RACE_MESSAGE), err);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async migrate(version) {
|
|
64
|
+
try {
|
|
65
|
+
const commands = migrationStore.migrate(this.config.schema, version, this.migrations);
|
|
66
|
+
await this.db.executeSql(commands);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
assert(err.message.includes(plans.MIGRATE_RACE_MESSAGE), err);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async next(version) {
|
|
73
|
+
const commands = migrationStore.next(this.config.schema, version, this.migrations);
|
|
74
|
+
await this.db.executeSql(commands);
|
|
75
|
+
}
|
|
76
|
+
async rollback(version) {
|
|
77
|
+
const commands = migrationStore.rollback(this.config.schema, version, this.migrations);
|
|
78
|
+
await this.db.executeSql(commands);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export default Contractor;
|
package/dist/db.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import EventEmitter from 'node:events';
|
|
2
|
+
import type * as types from './types.ts';
|
|
3
|
+
declare class Db extends EventEmitter implements types.IDatabase, types.EventsMixin {
|
|
4
|
+
private pool;
|
|
5
|
+
private config;
|
|
6
|
+
opened: boolean;
|
|
7
|
+
constructor(config: types.DatabaseOptions);
|
|
8
|
+
events: {
|
|
9
|
+
error: string;
|
|
10
|
+
};
|
|
11
|
+
open(): Promise<void>;
|
|
12
|
+
close(): Promise<void>;
|
|
13
|
+
executeSql(text: string, values?: unknown[]): Promise<import("pg").QueryResult<any>>;
|
|
14
|
+
}
|
|
15
|
+
export default Db;
|
|
16
|
+
//# sourceMappingURL=db.d.ts.map
|
package/dist/db.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,aAAa,CAAA;AAGtC,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAExC,cAAM,EAAG,SAAQ,YAAa,YAAW,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,WAAW;IACzE,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,MAAM,CAAuB;IAGrC,MAAM,EAAE,OAAO,CAAA;gBAEF,MAAM,EAAE,KAAK,CAAC,eAAe;IAY1C,MAAM;;MAEL;IAEK,IAAI;IAMJ,KAAK;IAOL,UAAU,CAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE;CAenD;AAED,eAAe,EAAE,CAAA"}
|
package/dist/db.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import EventEmitter from 'node:events';
|
|
2
|
+
import pg from 'pg';
|
|
3
|
+
import assert from 'node:assert';
|
|
4
|
+
class Db extends EventEmitter {
|
|
5
|
+
pool;
|
|
6
|
+
config;
|
|
7
|
+
/** @internal */
|
|
8
|
+
_pgbdb;
|
|
9
|
+
opened;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
super();
|
|
12
|
+
config.application_name = config.application_name || 'pgboss';
|
|
13
|
+
config.connectionTimeoutMillis = config.connectionTimeoutMillis || 10000;
|
|
14
|
+
// config.maxUses = config.maxUses || 1000
|
|
15
|
+
this.config = config;
|
|
16
|
+
this._pgbdb = true;
|
|
17
|
+
this.opened = false;
|
|
18
|
+
}
|
|
19
|
+
events = {
|
|
20
|
+
error: 'error'
|
|
21
|
+
};
|
|
22
|
+
async open() {
|
|
23
|
+
this.pool = new pg.Pool(this.config);
|
|
24
|
+
this.pool.on('error', error => this.emit('error', error));
|
|
25
|
+
this.opened = true;
|
|
26
|
+
}
|
|
27
|
+
async close() {
|
|
28
|
+
if (!this.pool.ending) {
|
|
29
|
+
this.opened = false;
|
|
30
|
+
await this.pool.end();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async executeSql(text, values) {
|
|
34
|
+
assert(this.opened, 'Database not opened. Call open() before executing SQL.');
|
|
35
|
+
// if (this.config.debug === true) {
|
|
36
|
+
// console.log(`${new Date().toISOString()}: DEBUG SQL`)
|
|
37
|
+
// console.log(text)
|
|
38
|
+
// if (values) {
|
|
39
|
+
// console.log(`${new Date().toISOString()}: DEBUG VALUES`)
|
|
40
|
+
// console.log(values)
|
|
41
|
+
// }
|
|
42
|
+
// }
|
|
43
|
+
return await this.pool.query(text, values);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export default Db;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import EventEmitter from 'node:events';
|
|
2
|
+
import type * as types from './types.ts';
|
|
3
|
+
import type { JobSpyInterface } from './spy.ts';
|
|
4
|
+
export { JOB_STATES as states } from './plans.ts';
|
|
5
|
+
export { QUEUE_POLICIES as policies } from './plans.ts';
|
|
6
|
+
export declare const events: types.Events;
|
|
7
|
+
export declare function getConstructionPlans(schema?: string): string;
|
|
8
|
+
export declare function getMigrationPlans(schema?: string, version?: number): string;
|
|
9
|
+
export declare function getRollbackPlans(schema?: string, version?: number): string;
|
|
10
|
+
export declare class PgBoss extends EventEmitter<types.PgBossEventMap> {
|
|
11
|
+
#private;
|
|
12
|
+
constructor(connectionString: string);
|
|
13
|
+
constructor(options: types.ConstructorOptions);
|
|
14
|
+
start(): Promise<this>;
|
|
15
|
+
stop(options?: types.StopOptions): Promise<void>;
|
|
16
|
+
send(request: types.Request): Promise<string | null>;
|
|
17
|
+
send(name: string, data?: object | null, options?: types.SendOptions): Promise<string | null>;
|
|
18
|
+
sendAfter(name: string, data: object | null, options: types.SendOptions | null, date: Date): Promise<string | null>;
|
|
19
|
+
sendAfter(name: string, data: object | null, options: types.SendOptions | null, dateString: string): Promise<string | null>;
|
|
20
|
+
sendAfter(name: string, data: object | null, options: types.SendOptions | null, seconds: number): Promise<string | null>;
|
|
21
|
+
sendThrottled(name: string, data: object | null, options: types.SendOptions | null, seconds: number, key?: string): Promise<string | null>;
|
|
22
|
+
sendDebounced(name: string, data: object | null, options: types.SendOptions | null, seconds: number, key?: string): Promise<string | null>;
|
|
23
|
+
insert(name: string, jobs: types.JobInsert[], options?: types.InsertOptions): Promise<string[] | null>;
|
|
24
|
+
fetch<T>(name: string, options: types.FetchOptions & {
|
|
25
|
+
includeMetadata: true;
|
|
26
|
+
}): Promise<types.JobWithMetadata<T>[]>;
|
|
27
|
+
fetch<T>(name: string, options?: types.FetchOptions): Promise<types.Job<T>[]>;
|
|
28
|
+
work<ReqData, ResData = any>(name: string, handler: types.WorkHandler<ReqData, ResData>): Promise<string>;
|
|
29
|
+
work<ReqData, ResData = any>(name: string, options: types.WorkOptions & {
|
|
30
|
+
includeMetadata: true;
|
|
31
|
+
}, handler: types.WorkWithMetadataHandler<ReqData, ResData>): Promise<string>;
|
|
32
|
+
work<ReqData, ResData = any>(name: string, options: types.WorkOptions, handler: types.WorkHandler<ReqData, ResData>): Promise<string>;
|
|
33
|
+
offWork(name: string, options?: types.OffWorkOptions): Promise<void>;
|
|
34
|
+
notifyWorker(workerId: string): void;
|
|
35
|
+
subscribe(event: string, name: string): Promise<void>;
|
|
36
|
+
unsubscribe(event: string, name: string): Promise<void>;
|
|
37
|
+
publish(event: string, data?: object, options?: types.SendOptions): Promise<void>;
|
|
38
|
+
cancel(name: string, id: string | string[], options?: types.ConnectionOptions): Promise<types.CommandResponse>;
|
|
39
|
+
resume(name: string, id: string | string[], options?: types.ConnectionOptions): Promise<types.CommandResponse>;
|
|
40
|
+
retry(name: string, id: string | string[], options?: types.ConnectionOptions): Promise<types.CommandResponse>;
|
|
41
|
+
deleteJob(name: string, id: string | string[], options?: types.ConnectionOptions): Promise<types.CommandResponse>;
|
|
42
|
+
deleteQueuedJobs(name: string): Promise<void>;
|
|
43
|
+
deleteStoredJobs(name: string): Promise<void>;
|
|
44
|
+
deleteAllJobs(name?: string): Promise<void>;
|
|
45
|
+
complete(name: string, id: string | string[], data?: object | null, options?: types.ConnectionOptions): Promise<types.CommandResponse>;
|
|
46
|
+
fail(name: string, id: string | string[], data?: object | null, options?: types.ConnectionOptions): Promise<types.CommandResponse>;
|
|
47
|
+
getJobById<T>(name: string, id: string, options?: types.ConnectionOptions): Promise<types.JobWithMetadata<T> | null>;
|
|
48
|
+
createQueue(name: string, options?: Omit<types.Queue, 'name'>): Promise<void>;
|
|
49
|
+
updateQueue(name: string, options?: types.UpdateQueueOptions): Promise<void>;
|
|
50
|
+
deleteQueue(name: string): Promise<void>;
|
|
51
|
+
getQueues(names?: string[]): Promise<types.QueueResult[]>;
|
|
52
|
+
getQueue(name: string): Promise<types.QueueResult | null>;
|
|
53
|
+
getQueueStats(name: string): Promise<types.QueueResult>;
|
|
54
|
+
supervise(name?: string): Promise<void>;
|
|
55
|
+
getSpy<T = object>(name: string): JobSpyInterface<T>;
|
|
56
|
+
clearSpies(): void;
|
|
57
|
+
isInstalled(): Promise<boolean>;
|
|
58
|
+
schemaVersion(): Promise<number | null>;
|
|
59
|
+
schedule(name: string, cron: string, data?: object | null, options?: types.ScheduleOptions): Promise<void>;
|
|
60
|
+
unschedule(name: string, key?: string): Promise<void>;
|
|
61
|
+
getSchedules(name?: string, key?: string): Promise<types.Schedule[]>;
|
|
62
|
+
getDb(): types.IDatabase;
|
|
63
|
+
}
|
|
64
|
+
export type { ConnectionOptions, ConstructorOptions, FetchOptions, IDatabase as Db, Job, JobFetchOptions, JobInsert, JobPollingOptions, JobStates, Events, JobWithMetadata, MaintenanceOptions, OffWorkOptions, Queue, QueuePolicy, QueueResult, Request, Schedule, ScheduleOptions, SchedulingOptions, SendOptions, StopOptions, WipData, WorkHandler, WorkOptions, WorkWithMetadataHandler, } from './types.ts';
|
|
65
|
+
export type { JobSpyInterface, JobSpyState, JobDataSelector, JobSelector, SpyJob, } from './spy.ts';
|
|
66
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,aAAa,CAAA;AAOtC,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAExC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C,OAAO,EAAE,UAAU,IAAI,MAAM,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,cAAc,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAA;AACvD,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,MAKzB,CAAA;AAEF,wBAAgB,oBAAoB,CAAE,MAAM,CAAC,EAAE,MAAM,UAEpD;AAED,wBAAgB,iBAAiB,CAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,UAEnE;AAED,wBAAgB,gBAAgB,CAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,UAElE;AAED,qBAAa,MAAO,SAAQ,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC;;gBAY/C,gBAAgB,EAAE,MAAM;gBACxB,OAAO,EAAE,KAAK,CAAC,kBAAkB;IAyCxC,KAAK,IAAK,OAAO,CAAC,IAAI,CAAC;IAkCvB,IAAI,CAAE,OAAO,GAAE,KAAK,CAAC,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA2C3D,IAAI,CAAE,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IACrD,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAK9F,SAAS,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IACpH,SAAS,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAC5H,SAAS,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKzH,aAAa,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI3I,aAAa,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI3I,MAAM,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IAIvG,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,YAAY,GAAG;QAAE,eAAe,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IACpH,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAK7E,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IACzG,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG;QAAE,eAAe,EAAE,IAAI,CAAA;KAAE,EAAE,OAAO,EAAE,KAAK,CAAC,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAC7K,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAKrI,OAAO,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrE,YAAY,CAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIrC,SAAS,CAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD,WAAW,CAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD,OAAO,CAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlF,MAAM,CAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;IAI/G,MAAM,CAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;IAI/G,KAAK,CAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;IAI9G,SAAS,CAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;IAIlH,gBAAgB,CAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,gBAAgB,CAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,aAAa,CAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C,QAAQ,CAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;IAIvI,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC;IAInI,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAIpH,WAAW,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9E,WAAW,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7E,WAAW,CAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,SAAS,CAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;IAI1D,QAAQ,CAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;IAI1D,aAAa,CAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC;IAIxD,SAAS,CAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,MAAM,CAAC,CAAC,GAAG,MAAM,EAAG,IAAI,EAAE,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC;IAIrD,UAAU,IAAK,IAAI;IAInB,WAAW,IAAK,OAAO,CAAC,OAAO,CAAC;IAIhC,aAAa,IAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIxC,QAAQ,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3G,UAAU,CAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD,YAAY,CAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IAIrE,KAAK,IAAK,KAAK,CAAC,SAAS;CAW1B;AAED,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,SAAS,IAAI,EAAE,EACf,GAAG,EACH,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,SAAS,EACT,MAAM,EACN,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,KAAK,EACL,WAAW,EACX,WAAW,EACX,OAAO,EACP,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,OAAO,EACP,WAAW,EACX,WAAW,EACX,uBAAuB,GACxB,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,eAAe,EACf,WAAW,EACX,eAAe,EACf,WAAW,EACX,MAAM,GACP,MAAM,UAAU,CAAA"}
|