@futdevpro/nts-dynamo 1.15.358 → 1.15.362
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/build/_collections/email-account.util.d.ts +70 -0
- package/build/_collections/email-account.util.d.ts.map +1 -0
- package/build/_collections/email-account.util.js +113 -0
- package/build/_collections/email-account.util.js.map +1 -0
- package/build/_modules/git-sync/_models/git-sync.interface.d.ts +94 -0
- package/build/_modules/git-sync/_models/git-sync.interface.d.ts.map +1 -0
- package/build/_modules/git-sync/_models/git-sync.interface.js +3 -0
- package/build/_modules/git-sync/_models/git-sync.interface.js.map +1 -0
- package/build/_modules/git-sync/git-sync-input.util.d.ts +28 -0
- package/build/_modules/git-sync/git-sync-input.util.d.ts.map +1 -0
- package/build/_modules/git-sync/git-sync-input.util.js +146 -0
- package/build/_modules/git-sync/git-sync-input.util.js.map +1 -0
- package/build/_modules/git-sync/git-sync.service.d.ts +54 -0
- package/build/_modules/git-sync/git-sync.service.d.ts.map +1 -0
- package/build/_modules/git-sync/git-sync.service.js +274 -0
- package/build/_modules/git-sync/git-sync.service.js.map +1 -0
- package/build/_modules/git-sync/index.d.ts +8 -0
- package/build/_modules/git-sync/index.d.ts.map +1 -0
- package/build/_modules/git-sync/index.js +11 -0
- package/build/_modules/git-sync/index.js.map +1 -0
- package/build/_modules/imap/_models/imap-mailbox-status.interface.d.ts +10 -0
- package/build/_modules/imap/_models/imap-mailbox-status.interface.d.ts.map +1 -0
- package/build/_modules/imap/_models/imap-mailbox-status.interface.js +3 -0
- package/build/_modules/imap/_models/imap-mailbox-status.interface.js.map +1 -0
- package/build/_modules/imap/_models/imap-message-meta.interface.d.ts +18 -0
- package/build/_modules/imap/_models/imap-message-meta.interface.d.ts.map +1 -0
- package/build/_modules/imap/_models/imap-message-meta.interface.js +3 -0
- package/build/_modules/imap/_models/imap-message-meta.interface.js.map +1 -0
- package/build/_modules/imap/_models/imap-sync.interface.d.ts +22 -0
- package/build/_modules/imap/_models/imap-sync.interface.d.ts.map +1 -0
- package/build/_modules/imap/_models/imap-sync.interface.js +3 -0
- package/build/_modules/imap/_models/imap-sync.interface.js.map +1 -0
- package/build/_modules/imap/_models/imap-transport.interface.d.ts +16 -0
- package/build/_modules/imap/_models/imap-transport.interface.d.ts.map +1 -0
- package/build/_modules/imap/_models/imap-transport.interface.js +3 -0
- package/build/_modules/imap/_models/imap-transport.interface.js.map +1 -0
- package/build/_modules/imap/imap-flow.transport.d.ts +58 -0
- package/build/_modules/imap/imap-flow.transport.d.ts.map +1 -0
- package/build/_modules/imap/imap-flow.transport.js +156 -0
- package/build/_modules/imap/imap-flow.transport.js.map +1 -0
- package/build/_modules/imap/imap-inbox.service.d.ts +36 -0
- package/build/_modules/imap/imap-inbox.service.d.ts.map +1 -0
- package/build/_modules/imap/imap-inbox.service.js +81 -0
- package/build/_modules/imap/imap-inbox.service.js.map +1 -0
- package/build/_modules/imap/index.d.ts +11 -0
- package/build/_modules/imap/index.d.ts.map +1 -0
- package/build/_modules/imap/index.js +14 -0
- package/build/_modules/imap/index.js.map +1 -0
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/package.json +26 -3
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { DyFM_Error } from '@futdevpro/fsm-dynamo';
|
|
2
|
+
import { DyNTS_EmailService, DyNTS_EmailService_Settings, DyNTS_EmailTemplateComponent } from '../_services/core/email.service';
|
|
3
|
+
/**
|
|
4
|
+
* BFR-OLDLIGHTSITE-010 — one SMTP account, named by a REFERENCE (an env-key prefix), resolved from the environment the
|
|
5
|
+
* FDP Keystore injects at runtime.
|
|
6
|
+
*
|
|
7
|
+
* @description `FDPNTS_emailCredentials` is bound to fixed `futdevpro.hu` accounts and fixed env keys, so a project
|
|
8
|
+
* with its own mailboxes (Oldlight: `contact@`, `support@`, `auto@oldlightgames.com`) had no way to register an SMTP
|
|
9
|
+
* transport without inventing a project-local secret flow. The Keystore already injects every secret as an env
|
|
10
|
+
* variable (runner job injection, `fdp env-pull`), so a reference is simply the key PREFIX:
|
|
11
|
+
*
|
|
12
|
+
* `credentialRef: 'OLS_SMTP_CONTACT'` → `OLS_SMTP_CONTACT_HOST`, `_PORT`, `_USER`, `_PASS`, optional `_SENDER_NAME`.
|
|
13
|
+
*
|
|
14
|
+
* ⛔ This util never adds or invents keys: the project names them, and the values live in the Keystore
|
|
15
|
+
* (`fdp-keystore-secrets`). ⛔ No value ever reaches a log, an error or a result — only key NAMES and states.
|
|
16
|
+
*/
|
|
17
|
+
export interface DyNTS_EmailAccountRef_Interface {
|
|
18
|
+
/** The env-key prefix of the account (letters, digits, underscore), e.g. `OLS_SMTP_CONTACT`. */
|
|
19
|
+
credentialRef: string;
|
|
20
|
+
/** Passed to `DyNTS_EmailService` (template root). */
|
|
21
|
+
rootPath: string;
|
|
22
|
+
templateComponents?: DyNTS_EmailTemplateComponent[];
|
|
23
|
+
/** The environment to read (default: `process.env`) — a test seam. */
|
|
24
|
+
env?: NodeJS.ProcessEnv;
|
|
25
|
+
}
|
|
26
|
+
/** What the reference resolved to. Carries key NAMES only — never a value. */
|
|
27
|
+
export type DyNTS_EmailAccountResolution_Type = {
|
|
28
|
+
status: 'configured';
|
|
29
|
+
credentialRef: string;
|
|
30
|
+
settings: DyNTS_EmailService_Settings;
|
|
31
|
+
} | {
|
|
32
|
+
status: 'absent';
|
|
33
|
+
credentialRef: string;
|
|
34
|
+
missingKeys: string[];
|
|
35
|
+
} | {
|
|
36
|
+
status: 'invalid';
|
|
37
|
+
credentialRef: string;
|
|
38
|
+
problems: string[];
|
|
39
|
+
};
|
|
40
|
+
/** Keystore-ref based SMTP account bootstrap (BFR-OLDLIGHTSITE-010). */
|
|
41
|
+
export declare class DyNTS_EmailAccount_Util {
|
|
42
|
+
/** The env-key names a reference expands to (`_SENDER_NAME` is optional). */
|
|
43
|
+
static keysOf(credentialRef: string): {
|
|
44
|
+
required: string[];
|
|
45
|
+
optional: string[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Resolves the reference. `absent` = at least one required key is missing or empty (the account is simply not
|
|
49
|
+
* configured on this host → the caller answers 503); `invalid` = the keys are there but unusable (a wrong port, a
|
|
50
|
+
* user that is not an e-mail address). Never throws, never returns a value in a problem text.
|
|
51
|
+
*/
|
|
52
|
+
static resolve(ref: DyNTS_EmailAccountRef_Interface): DyNTS_EmailAccountResolution_Type;
|
|
53
|
+
/**
|
|
54
|
+
* Creates the `DyNTS_EmailService` ONLY when the account resolves; otherwise returns `null` with the resolution, and
|
|
55
|
+
* logs WHICH keys are missing / wrong (names, never values). The service is not registered anywhere — the caller
|
|
56
|
+
* decides (e.g. its email-service collection).
|
|
57
|
+
*/
|
|
58
|
+
static createEmailService(ref: DyNTS_EmailAccountRef_Interface): {
|
|
59
|
+
service: DyNTS_EmailService | null;
|
|
60
|
+
resolution: DyNTS_EmailAccountResolution_Type;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* The degraded-mode error for a caller that needs the account NOW: 503, with the key NAMES the operator has to set in
|
|
64
|
+
* the Keystore (no value). `configured` → `null`.
|
|
65
|
+
*/
|
|
66
|
+
static unavailableError(resolution: DyNTS_EmailAccountResolution_Type): DyFM_Error | null;
|
|
67
|
+
/** Key names / problems only — the one text that may reach a log or an error. */
|
|
68
|
+
private static describe;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=email-account.util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-account.util.d.ts","sourceRoot":"","sources":["../../src/_collections/email-account.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAY,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EACL,kBAAkB,EAAE,2BAA2B,EAAE,4BAA4B,EAC9E,MAAM,iCAAiC,CAAC;AAGzC;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,+BAA+B;IAC9C,gGAAgG;IAChG,aAAa,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,4BAA4B,EAAE,CAAC;IACpD,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,8EAA8E;AAC9E,MAAM,MAAM,iCAAiC,GACzC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,2BAA2B,CAAA;CAAE,GACtF;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,GAClE;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAKrE,wEAAwE;AACxE,qBAAa,uBAAuB;IAElC,6EAA6E;IAC7E,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE;IAOhF;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,+BAA+B,GAAG,iCAAiC;IAwDvF;;;;OAIG;IACH,MAAM,CAAC,kBAAkB,CACvB,GAAG,EAAE,+BAA+B,GACnC;QAAE,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,iCAAiC,CAAA;KAAE;IAexF;;;OAGG;IACH,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,iCAAiC,GAAG,UAAU,GAAG,IAAI;IAczF,iFAAiF;IACjF,OAAO,CAAC,MAAM,CAAC,QAAQ;CAUxB"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DyNTS_EmailAccount_Util = void 0;
|
|
4
|
+
const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
|
|
5
|
+
const email_service_1 = require("../_services/core/email.service");
|
|
6
|
+
const global_settings_const_1 = require("./global-settings.const");
|
|
7
|
+
/** The keys an account reference expands to (the required ones). */
|
|
8
|
+
const REQUIRED_SUFFIXES = ['HOST', 'PORT', 'USER', 'PASS'];
|
|
9
|
+
/** Keystore-ref based SMTP account bootstrap (BFR-OLDLIGHTSITE-010). */
|
|
10
|
+
class DyNTS_EmailAccount_Util {
|
|
11
|
+
/** The env-key names a reference expands to (`_SENDER_NAME` is optional). */
|
|
12
|
+
static keysOf(credentialRef) {
|
|
13
|
+
return {
|
|
14
|
+
required: REQUIRED_SUFFIXES.map((suffix) => `${credentialRef}_${suffix}`),
|
|
15
|
+
optional: [`${credentialRef}_SENDER_NAME`],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolves the reference. `absent` = at least one required key is missing or empty (the account is simply not
|
|
20
|
+
* configured on this host → the caller answers 503); `invalid` = the keys are there but unusable (a wrong port, a
|
|
21
|
+
* user that is not an e-mail address). Never throws, never returns a value in a problem text.
|
|
22
|
+
*/
|
|
23
|
+
static resolve(ref) {
|
|
24
|
+
const credentialRef = String(ref?.credentialRef ?? '');
|
|
25
|
+
if (!/^[A-Z][A-Z0-9_]{0,63}$/.test(credentialRef)) {
|
|
26
|
+
return {
|
|
27
|
+
status: 'invalid',
|
|
28
|
+
credentialRef: credentialRef,
|
|
29
|
+
problems: ['the credentialRef must be an UPPER_SNAKE env-key prefix (e.g. OLS_SMTP_CONTACT)'],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const env = ref.env ?? process.env;
|
|
33
|
+
const read = (key) => String(env[key] ?? '').trim();
|
|
34
|
+
const keys = DyNTS_EmailAccount_Util.keysOf(credentialRef);
|
|
35
|
+
const missingKeys = keys.required.filter((key) => !read(key));
|
|
36
|
+
if (missingKeys.length) {
|
|
37
|
+
return { status: 'absent', credentialRef: credentialRef, missingKeys: missingKeys };
|
|
38
|
+
}
|
|
39
|
+
const host = read(`${credentialRef}_HOST`);
|
|
40
|
+
const portText = read(`${credentialRef}_PORT`);
|
|
41
|
+
const port = Number(portText);
|
|
42
|
+
const user = read(`${credentialRef}_USER`);
|
|
43
|
+
const problems = [];
|
|
44
|
+
if (!/^\d+$/.test(portText) || port < 1 || port > 65535) {
|
|
45
|
+
problems.push(`${credentialRef}_PORT is not a port number (1-65535)`);
|
|
46
|
+
}
|
|
47
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(user)) {
|
|
48
|
+
problems.push(`${credentialRef}_USER is not an e-mail address`);
|
|
49
|
+
}
|
|
50
|
+
if (/\s/.test(host)) {
|
|
51
|
+
problems.push(`${credentialRef}_HOST contains whitespace`);
|
|
52
|
+
}
|
|
53
|
+
if (problems.length) {
|
|
54
|
+
return { status: 'invalid', credentialRef: credentialRef, problems: problems };
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
status: 'configured',
|
|
58
|
+
credentialRef: credentialRef,
|
|
59
|
+
settings: {
|
|
60
|
+
host: host,
|
|
61
|
+
port: port,
|
|
62
|
+
email: user,
|
|
63
|
+
// the password is NOT trimmed: surrounding spaces may be part of it
|
|
64
|
+
pass: String(env[`${credentialRef}_PASS`] ?? ''),
|
|
65
|
+
senderName: read(`${credentialRef}_SENDER_NAME`) || user,
|
|
66
|
+
rootPath: ref.rootPath,
|
|
67
|
+
templateComponents: ref.templateComponents,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Creates the `DyNTS_EmailService` ONLY when the account resolves; otherwise returns `null` with the resolution, and
|
|
73
|
+
* logs WHICH keys are missing / wrong (names, never values). The service is not registered anywhere — the caller
|
|
74
|
+
* decides (e.g. its email-service collection).
|
|
75
|
+
*/
|
|
76
|
+
static createEmailService(ref) {
|
|
77
|
+
const resolution = DyNTS_EmailAccount_Util.resolve(ref);
|
|
78
|
+
if (resolution.status !== 'configured') {
|
|
79
|
+
fsm_dynamo_1.DyFM_Log.warn(`[DyNTS email-account] "${resolution.credentialRef}" is not usable (${resolution.status}): `
|
|
80
|
+
+ DyNTS_EmailAccount_Util.describe(resolution));
|
|
81
|
+
return { service: null, resolution: resolution };
|
|
82
|
+
}
|
|
83
|
+
return { service: new email_service_1.DyNTS_EmailService(resolution.settings), resolution: resolution };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The degraded-mode error for a caller that needs the account NOW: 503, with the key NAMES the operator has to set in
|
|
87
|
+
* the Keystore (no value). `configured` → `null`.
|
|
88
|
+
*/
|
|
89
|
+
static unavailableError(resolution) {
|
|
90
|
+
if (resolution.status === 'configured') {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return new fsm_dynamo_1.DyFM_Error({
|
|
94
|
+
status: 503,
|
|
95
|
+
errorCode: `${global_settings_const_1.DyNTS_global_settings.systemShortCodeName}|DyNTS-EMAIL-ACCOUNT-${resolution.status.toUpperCase()}`,
|
|
96
|
+
message: `SMTP account "${resolution.credentialRef}" is ${resolution.status}: `
|
|
97
|
+
+ DyNTS_EmailAccount_Util.describe(resolution),
|
|
98
|
+
userMessage: 'E-mail sending is not available at the moment. Please try again later.',
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/** Key names / problems only — the one text that may reach a log or an error. */
|
|
102
|
+
static describe(resolution) {
|
|
103
|
+
if (resolution.status === 'absent') {
|
|
104
|
+
return `missing Keystore keys: ${resolution.missingKeys.join(', ')}`;
|
|
105
|
+
}
|
|
106
|
+
if (resolution.status === 'invalid') {
|
|
107
|
+
return resolution.problems.join('; ');
|
|
108
|
+
}
|
|
109
|
+
return 'configured';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.DyNTS_EmailAccount_Util = DyNTS_EmailAccount_Util;
|
|
113
|
+
//# sourceMappingURL=email-account.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-account.util.js","sourceRoot":"","sources":["../../src/_collections/email-account.util.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/** BFR-OLDLIGHTSITE-003 — one file the caller wants in the repository, byte-exact. */
|
|
2
|
+
export interface DyNTS_GitSyncFile_Interface {
|
|
3
|
+
/** A repository-relative path with `/` separators (no `..`, no absolute path, nothing under `.git`). */
|
|
4
|
+
path: string;
|
|
5
|
+
/** Written exactly as given (UTF-8, no line-ending conversion). */
|
|
6
|
+
content: string;
|
|
7
|
+
}
|
|
8
|
+
/** BFR-OLDLIGHTSITE-003 — one `sync` call. */
|
|
9
|
+
export interface DyNTS_GitSyncRequest_Interface {
|
|
10
|
+
files: DyNTS_GitSyncFile_Interface[];
|
|
11
|
+
/** The commit message of the ONE commit this call may create. */
|
|
12
|
+
message: string;
|
|
13
|
+
/**
|
|
14
|
+
* Directories the caller OWNS completely (e.g. `story-points`): a tracked file under them that is NOT in `files` is
|
|
15
|
+
* removed in the same commit. Nothing outside these directories is ever removed.
|
|
16
|
+
*/
|
|
17
|
+
prune?: string[];
|
|
18
|
+
}
|
|
19
|
+
/** BFR-OLDLIGHTSITE-003 — one git command of the run log (no secret: the token never travels in arguments). */
|
|
20
|
+
export interface DyNTS_GitSyncLogEntry_Interface {
|
|
21
|
+
step: string;
|
|
22
|
+
command: string;
|
|
23
|
+
exitCode: number;
|
|
24
|
+
ms: number;
|
|
25
|
+
}
|
|
26
|
+
/** BFR-OLDLIGHTSITE-003 — the outcome of a successful `sync`. */
|
|
27
|
+
export interface DyNTS_GitSyncResult_Interface {
|
|
28
|
+
/** `pushed` = one new commit is on the remote branch; `unchanged` = the files already matched, nothing committed. */
|
|
29
|
+
status: 'pushed' | 'unchanged';
|
|
30
|
+
/** The remote branch head after the call (the new commit, or the unchanged head). */
|
|
31
|
+
commit: string;
|
|
32
|
+
/** Added or modified paths, sorted. */
|
|
33
|
+
changedFiles: string[];
|
|
34
|
+
/** Paths removed through `prune`, sorted. */
|
|
35
|
+
removedFiles: string[];
|
|
36
|
+
/** 1, or 2 when the first push was rejected because the remote moved meanwhile. */
|
|
37
|
+
attempts: number;
|
|
38
|
+
durationMs: number;
|
|
39
|
+
log: DyNTS_GitSyncLogEntry_Interface[];
|
|
40
|
+
}
|
|
41
|
+
/** What a git command returned. */
|
|
42
|
+
export interface DyNTS_GitRunResult_Interface {
|
|
43
|
+
exitCode: number;
|
|
44
|
+
stdout: string;
|
|
45
|
+
stderr: string;
|
|
46
|
+
}
|
|
47
|
+
/** Runs `git <args>` — the default spawns the git binary; a test can wrap or replace it. */
|
|
48
|
+
export type DyNTS_GitRunner_Type = (args: string[], options: {
|
|
49
|
+
cwd: string;
|
|
50
|
+
env: NodeJS.ProcessEnv;
|
|
51
|
+
timeoutMs: number;
|
|
52
|
+
}) => Promise<DyNTS_GitRunResult_Interface>;
|
|
53
|
+
/** BFR-OLDLIGHTSITE-003 — one synchronised repository. */
|
|
54
|
+
export interface DyNTS_GitSync_Settings_Interface {
|
|
55
|
+
/** `https://…` (then `credentialRef` is required) or `file://…`. ⛔ Never with credentials inside the URL. */
|
|
56
|
+
repoUrl: string;
|
|
57
|
+
/** The branch to follow and push (it must already exist on the remote). */
|
|
58
|
+
branch: string;
|
|
59
|
+
/**
|
|
60
|
+
* A directory OWNED by this service: it is cloned on first use and force-reset to the remote branch on every call.
|
|
61
|
+
* An existing directory that is not a clone of `repoUrl` is refused, never touched.
|
|
62
|
+
*/
|
|
63
|
+
workdir: string;
|
|
64
|
+
/** The env-key prefix of the token: `OLS_ARCHIVE_GIT` → `OLS_ARCHIVE_GIT_TOKEN` (injected by the FDP Keystore). */
|
|
65
|
+
credentialRef?: string;
|
|
66
|
+
/** The HTTP Basic user sent with the token (default `x-access-token` — GitHub accepts it for PATs and app tokens). */
|
|
67
|
+
tokenUser?: string;
|
|
68
|
+
author: {
|
|
69
|
+
name: string;
|
|
70
|
+
email: string;
|
|
71
|
+
};
|
|
72
|
+
/** The environment to read the token from (default `process.env`) — a test seam. */
|
|
73
|
+
env?: NodeJS.ProcessEnv;
|
|
74
|
+
runner?: DyNTS_GitRunner_Type;
|
|
75
|
+
/** Per git command (default 120 000 ms). */
|
|
76
|
+
timeoutMs?: number;
|
|
77
|
+
}
|
|
78
|
+
/** What `credentialRef` resolved to. Carries key NAMES only — never a value. */
|
|
79
|
+
export type DyNTS_GitSyncCredential_Type = {
|
|
80
|
+
status: 'none';
|
|
81
|
+
} | {
|
|
82
|
+
status: 'configured';
|
|
83
|
+
credentialRef: string;
|
|
84
|
+
tokenKey: string;
|
|
85
|
+
} | {
|
|
86
|
+
status: 'absent';
|
|
87
|
+
credentialRef: string;
|
|
88
|
+
missingKeys: string[];
|
|
89
|
+
} | {
|
|
90
|
+
status: 'invalid';
|
|
91
|
+
credentialRef: string;
|
|
92
|
+
problems: string[];
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=git-sync.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-sync.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/git-sync/_models/git-sync.interface.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,MAAM,WAAW,2BAA2B;IAC1C,wGAAwG;IACxG,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,8CAA8C;AAC9C,MAAM,WAAW,8BAA8B;IAC7C,KAAK,EAAE,2BAA2B,EAAE,CAAC;IACrC,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,+GAA+G;AAC/G,MAAM,WAAW,+BAA+B;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,iEAAiE;AACjE,MAAM,WAAW,6BAA6B;IAC5C,qHAAqH;IACrH,MAAM,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC/B,qFAAqF;IACrF,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,+BAA+B,EAAE,CAAC;CACxC;AAED,mCAAmC;AACnC,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4FAA4F;AAC5F,MAAM,MAAM,oBAAoB,GAAG,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,KAChE,OAAO,CAAC,4BAA4B,CAAC,CAAC;AAE3C,0DAA0D;AAC1D,MAAM,WAAW,gCAAgC;IAC/C,6GAA6G;IAC7G,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,mHAAmH;IACnH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sHAAsH;IACtH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,oFAAoF;IACpF,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,gFAAgF;AAChF,MAAM,MAAM,4BAA4B,GACpC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACjE;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,GAClE;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-sync.interface.js","sourceRoot":"","sources":["../../../../src/_modules/git-sync/_models/git-sync.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DyNTS_GitSync_Settings_Interface, DyNTS_GitSyncCredential_Type, DyNTS_GitSyncFile_Interface, DyNTS_GitSyncRequest_Interface } from './_models/git-sync.interface';
|
|
2
|
+
/** A validated request: the message trimmed, the prune directories normalised and deduplicated. */
|
|
3
|
+
export interface DyNTS_GitSyncPlan_Interface {
|
|
4
|
+
files: DyNTS_GitSyncFile_Interface[];
|
|
5
|
+
message: string;
|
|
6
|
+
prune: string[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* BFR-OLDLIGHTSITE-003 — everything checked BEFORE the first git command: the request (paths, message, prune
|
|
10
|
+
* directories), the settings (URL, branch, author) and the Keystore reference of the token.
|
|
11
|
+
*
|
|
12
|
+
* @description A bad input is a caller error (400) and never reaches git or the filesystem.
|
|
13
|
+
*/
|
|
14
|
+
export declare class DyNTS_GitSyncInput_Util {
|
|
15
|
+
/** The env-key a reference expands to. */
|
|
16
|
+
static keysOf(credentialRef: string): string[];
|
|
17
|
+
/** Resolves `credentialRef`; never throws and never returns the value. */
|
|
18
|
+
static resolveCredential(settings: DyNTS_GitSync_Settings_Interface): DyNTS_GitSyncCredential_Type;
|
|
19
|
+
/** Checks the settings; returns the problems (empty = usable). */
|
|
20
|
+
static settingsProblems(settings: DyNTS_GitSync_Settings_Interface): string[];
|
|
21
|
+
/** Validates and normalises a request, or throws a 400. */
|
|
22
|
+
static plan(request: DyNTS_GitSyncRequest_Interface): DyNTS_GitSyncPlan_Interface;
|
|
23
|
+
/** Why a repository-relative path is unsafe (null = safe). */
|
|
24
|
+
static pathProblem(path: unknown): string | null;
|
|
25
|
+
/** A conservative branch-name check (no option-like or ref-breaking names). */
|
|
26
|
+
static isSafeBranch(branch: string): boolean;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=git-sync-input.util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-sync-input.util.d.ts","sourceRoot":"","sources":["../../../src/_modules/git-sync/git-sync-input.util.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,gCAAgC,EAAE,4BAA4B,EAAE,2BAA2B,EAC3F,8BAA8B,EAC/B,MAAM,8BAA8B,CAAC;AAEtC,mGAAmG;AACnG,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,2BAA2B,EAAE,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;GAKG;AACH,qBAAa,uBAAuB;IAElC,0CAA0C;IAC1C,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE;IAI9C,0EAA0E;IAC1E,MAAM,CAAC,iBAAiB,CAAC,QAAQ,EAAE,gCAAgC,GAAG,4BAA4B;IAyBlG,kEAAkE;IAClE,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,gCAAgC,GAAG,MAAM,EAAE;IAqC7E,2DAA2D;IAC3D,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,8BAA8B,GAAG,2BAA2B;IAyDjF,8DAA8D;IAC9D,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI;IAuBhD,+EAA+E;IAC/E,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;CAK7C"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DyNTS_GitSyncInput_Util = void 0;
|
|
4
|
+
const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
|
|
5
|
+
const global_settings_const_1 = require("../../_collections/global-settings.const");
|
|
6
|
+
/**
|
|
7
|
+
* BFR-OLDLIGHTSITE-003 — everything checked BEFORE the first git command: the request (paths, message, prune
|
|
8
|
+
* directories), the settings (URL, branch, author) and the Keystore reference of the token.
|
|
9
|
+
*
|
|
10
|
+
* @description A bad input is a caller error (400) and never reaches git or the filesystem.
|
|
11
|
+
*/
|
|
12
|
+
class DyNTS_GitSyncInput_Util {
|
|
13
|
+
/** The env-key a reference expands to. */
|
|
14
|
+
static keysOf(credentialRef) {
|
|
15
|
+
return [`${credentialRef}_TOKEN`];
|
|
16
|
+
}
|
|
17
|
+
/** Resolves `credentialRef`; never throws and never returns the value. */
|
|
18
|
+
static resolveCredential(settings) {
|
|
19
|
+
if (settings.credentialRef === undefined) {
|
|
20
|
+
return { status: 'none' };
|
|
21
|
+
}
|
|
22
|
+
const credentialRef = String(settings.credentialRef);
|
|
23
|
+
if (!/^[A-Z][A-Z0-9_]{0,63}$/.test(credentialRef)) {
|
|
24
|
+
return {
|
|
25
|
+
status: 'invalid',
|
|
26
|
+
credentialRef: credentialRef,
|
|
27
|
+
problems: ['the credentialRef must be an UPPER_SNAKE env-key prefix (e.g. OLS_ARCHIVE_GIT)'],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const tokenKey = DyNTS_GitSyncInput_Util.keysOf(credentialRef)[0];
|
|
31
|
+
const env = settings.env ?? process.env;
|
|
32
|
+
if (!String(env[tokenKey] ?? '').trim()) {
|
|
33
|
+
return { status: 'absent', credentialRef: credentialRef, missingKeys: [tokenKey] };
|
|
34
|
+
}
|
|
35
|
+
return { status: 'configured', credentialRef: credentialRef, tokenKey: tokenKey };
|
|
36
|
+
}
|
|
37
|
+
/** Checks the settings; returns the problems (empty = usable). */
|
|
38
|
+
static settingsProblems(settings) {
|
|
39
|
+
const problems = [];
|
|
40
|
+
let url = null;
|
|
41
|
+
try {
|
|
42
|
+
url = new URL(String(settings?.repoUrl ?? ''));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
problems.push('repoUrl is not a URL');
|
|
46
|
+
}
|
|
47
|
+
if (url) {
|
|
48
|
+
if (url.username || url.password) {
|
|
49
|
+
problems.push('repoUrl must not contain credentials — pass the token through credentialRef (the FDP Keystore)');
|
|
50
|
+
}
|
|
51
|
+
if (url.protocol === 'https:' && settings.credentialRef === undefined) {
|
|
52
|
+
problems.push('an https repoUrl needs a credentialRef');
|
|
53
|
+
}
|
|
54
|
+
if (url.protocol !== 'https:' && url.protocol !== 'file:') {
|
|
55
|
+
problems.push(`repoUrl protocol ${url.protocol} is not supported (https: or file:)`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!DyNTS_GitSyncInput_Util.isSafeBranch(String(settings?.branch ?? ''))) {
|
|
59
|
+
problems.push('branch is not a safe branch name');
|
|
60
|
+
}
|
|
61
|
+
if (!String(settings?.workdir ?? '').trim()) {
|
|
62
|
+
problems.push('workdir is required');
|
|
63
|
+
}
|
|
64
|
+
const authorName = String(settings?.author?.name ?? '').trim();
|
|
65
|
+
if (!authorName || !/^[^\s@]+@[^\s@]+$/.test(String(settings?.author?.email ?? ''))) {
|
|
66
|
+
problems.push('author needs a name and an e-mail address');
|
|
67
|
+
}
|
|
68
|
+
return problems;
|
|
69
|
+
}
|
|
70
|
+
/** Validates and normalises a request, or throws a 400. */
|
|
71
|
+
static plan(request) {
|
|
72
|
+
const problems = [];
|
|
73
|
+
const files = Array.isArray(request?.files) ? request.files : [];
|
|
74
|
+
const seen = new Set();
|
|
75
|
+
if (!Array.isArray(request?.files)) {
|
|
76
|
+
problems.push('files must be an array');
|
|
77
|
+
}
|
|
78
|
+
files.forEach((file, index) => {
|
|
79
|
+
const problem = DyNTS_GitSyncInput_Util.pathProblem(file?.path);
|
|
80
|
+
if (problem) {
|
|
81
|
+
problems.push(`files[${index}]: ${problem}`);
|
|
82
|
+
}
|
|
83
|
+
else if (seen.has(file.path.toLowerCase())) {
|
|
84
|
+
// case-insensitive: two paths that differ only in case collide on Windows and macOS checkouts
|
|
85
|
+
problems.push(`files[${index}]: duplicate path ${file.path}`);
|
|
86
|
+
}
|
|
87
|
+
if (typeof file?.content !== 'string') {
|
|
88
|
+
problems.push(`files[${index}]: content must be a string`);
|
|
89
|
+
}
|
|
90
|
+
seen.add(String(file?.path ?? '').toLowerCase());
|
|
91
|
+
});
|
|
92
|
+
const prune = (request?.prune ?? []).map((dir) => String(dir ?? '').replace(/\/+$/, ''));
|
|
93
|
+
prune.forEach((dir, index) => {
|
|
94
|
+
const problem = DyNTS_GitSyncInput_Util.pathProblem(dir);
|
|
95
|
+
if (problem) {
|
|
96
|
+
problems.push(`prune[${index}]: ${problem}`);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const message = String(request?.message ?? '').trim();
|
|
100
|
+
if (!message || message.length > 10000) {
|
|
101
|
+
problems.push('message must be 1–10000 characters');
|
|
102
|
+
}
|
|
103
|
+
if (problems.length) {
|
|
104
|
+
throw new fsm_dynamo_1.DyFM_Error({
|
|
105
|
+
status: 400,
|
|
106
|
+
errorCode: `${global_settings_const_1.DyNTS_global_settings.systemShortCodeName}|DyNTS-GITSYNC-IN0`,
|
|
107
|
+
message: `GitSync request rejected: ${problems.join('; ')}`,
|
|
108
|
+
userMessage: 'The files to synchronise are invalid.',
|
|
109
|
+
additionalContent: { problems: problems },
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
files: files,
|
|
114
|
+
message: message,
|
|
115
|
+
prune: [...new Set(prune)].sort(),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Why a repository-relative path is unsafe (null = safe). */
|
|
119
|
+
static pathProblem(path) {
|
|
120
|
+
if (typeof path !== 'string' || !path) {
|
|
121
|
+
return 'the path is empty';
|
|
122
|
+
}
|
|
123
|
+
if (path.length > 400) {
|
|
124
|
+
return 'the path is longer than 400 characters';
|
|
125
|
+
}
|
|
126
|
+
if (/[\\:\0]/.test(path) || path.startsWith('/')) {
|
|
127
|
+
return `${path} is not a relative path with / separators`;
|
|
128
|
+
}
|
|
129
|
+
const segments = path.split('/');
|
|
130
|
+
if (segments.some((segment) => !segment || segment === '.' || segment === '..')) {
|
|
131
|
+
return `${path} has an empty, . or .. segment`;
|
|
132
|
+
}
|
|
133
|
+
if (segments.some((segment) => segment.toLowerCase() === '.git')) {
|
|
134
|
+
return `${path} is inside .git`;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
/** A conservative branch-name check (no option-like or ref-breaking names). */
|
|
139
|
+
static isSafeBranch(branch) {
|
|
140
|
+
return /^[A-Za-z0-9._/-]{1,200}$/.test(branch)
|
|
141
|
+
&& !branch.startsWith('-') && !branch.startsWith('/') && !branch.endsWith('/')
|
|
142
|
+
&& !branch.includes('..') && !branch.includes('//') && !branch.endsWith('.lock') && !branch.endsWith('.');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.DyNTS_GitSyncInput_Util = DyNTS_GitSyncInput_Util;
|
|
146
|
+
//# sourceMappingURL=git-sync-input.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-sync-input.util.js","sourceRoot":"","sources":["../../../src/_modules/git-sync/git-sync-input.util.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { DyNTS_GitRunner_Type, DyNTS_GitSync_Settings_Interface, DyNTS_GitSyncRequest_Interface, DyNTS_GitSyncResult_Interface } from './_models/git-sync.interface';
|
|
2
|
+
/**
|
|
3
|
+
* BFR-OLDLIGHTSITE-003 — synchronises a caller-built file set into a git repository as ONE commit, pushed.
|
|
4
|
+
*
|
|
5
|
+
* @description Per call: clone (first use) or fetch → force-reset the owned workdir to the remote branch → write the
|
|
6
|
+
* files byte-exact → remove tracked files the caller no longer lists under its `prune` directories → ONE commit →
|
|
7
|
+
* push (fast-forward only: a push is never forced). Nothing changed → no commit (`unchanged`). The remote moved
|
|
8
|
+
* between fetch and push → the whole step runs once more on the new head.
|
|
9
|
+
*
|
|
10
|
+
* The token (`<credentialRef>_TOKEN`, FDP Keystore) reaches git ONLY as an environment-scoped `http.extraHeader`
|
|
11
|
+
* (`GIT_CONFIG_*`): never in an argument (visible in the process list), never in the URL, never in `.git/config`.
|
|
12
|
+
* Every error text is redacted — the token literal included.
|
|
13
|
+
*/
|
|
14
|
+
export declare class DyNTS_GitSync_Service {
|
|
15
|
+
private readonly settings;
|
|
16
|
+
private readonly runner;
|
|
17
|
+
private readonly timeoutMs;
|
|
18
|
+
/** The calls of this instance run one after another — they share one workdir. */
|
|
19
|
+
private queue;
|
|
20
|
+
/** Validates the settings (a 400 on a configuration error); the token is only read when `sync` runs. */
|
|
21
|
+
constructor(settings: DyNTS_GitSync_Settings_Interface);
|
|
22
|
+
/** The default runner: the `git` binary, no shell, bounded time and output. */
|
|
23
|
+
static readonly defaultRunner: DyNTS_GitRunner_Type;
|
|
24
|
+
/**
|
|
25
|
+
* One synchronisation step — see the class description. Concurrent calls on the same instance are queued (one
|
|
26
|
+
* workdir); ⚠️ two INSTANCES or processes must not share a workdir.
|
|
27
|
+
*/
|
|
28
|
+
sync(request: DyNTS_GitSyncRequest_Interface): Promise<DyNTS_GitSyncResult_Interface>;
|
|
29
|
+
private syncNow;
|
|
30
|
+
/** Clone on first use; otherwise verify the clone's origin, fetch and force-reset to the remote branch. */
|
|
31
|
+
private prepareWorkdir;
|
|
32
|
+
/** Writes every file byte-exact; a symbolic link on the way is refused (it could point outside the workdir). */
|
|
33
|
+
private writeFiles;
|
|
34
|
+
/** Removes the tracked files under the prune directories that the caller no longer lists. */
|
|
35
|
+
private pruneFiles;
|
|
36
|
+
/** The absolute path of a repository-relative one — and a last check that it stays inside the workdir. */
|
|
37
|
+
private inside;
|
|
38
|
+
/** Refuses a path whose existing parent is a symbolic link. */
|
|
39
|
+
private assertNoLink;
|
|
40
|
+
/** `git diff --name-status -z` → added/modified and deleted paths, sorted. */
|
|
41
|
+
private parseNameStatus;
|
|
42
|
+
private head;
|
|
43
|
+
/** The child environment: no prompt, and the token — if any — as an URL-scoped extra header. */
|
|
44
|
+
private gitEnv;
|
|
45
|
+
/** Values that must never appear in a log or error text (the token and its header form). */
|
|
46
|
+
private secrets;
|
|
47
|
+
/** Runs one git command, logs it, and throws a rich, redacted error on failure (unless `allowFailure`). */
|
|
48
|
+
private git;
|
|
49
|
+
private failure;
|
|
50
|
+
private refusal;
|
|
51
|
+
/** The generic secret redaction, plus the literal token values of this sync. */
|
|
52
|
+
private redact;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=git-sync.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-sync.service.d.ts","sourceRoot":"","sources":["../../../src/_modules/git-sync/git-sync.service.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,oBAAoB,EAAgC,gCAAgC,EACtB,8BAA8B,EAC5F,6BAA6B,EAC9B,MAAM,8BAA8B,CAAC;AAWtC;;;;;;;;;;;GAWG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,iFAAiF;IACjF,OAAO,CAAC,KAAK,CAAuC;IAEpD,wGAAwG;gBAC5F,QAAQ,EAAE,gCAAgC;IAkBtD,+EAA+E;IAC/E,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,oBAAoB,CAcjD;IAEF;;;OAGG;IACG,IAAI,CAAC,OAAO,EAAE,8BAA8B,GAAG,OAAO,CAAC,6BAA6B,CAAC;YA0B7E,OAAO;IAuDrB,2GAA2G;YAC7F,cAAc;IAkC5B,gHAAgH;YAClG,UAAU;IAUxB,6FAA6F;YAC/E,UAAU;IAsBxB,0GAA0G;IAC1G,OAAO,CAAC,MAAM;IAUd,+DAA+D;YACjD,YAAY;IAc1B,8EAA8E;IAC9E,OAAO,CAAC,eAAe;YAYT,IAAI;IAIlB,gGAAgG;IAChG,OAAO,CAAC,MAAM;IA8Bd,4FAA4F;IAC5F,OAAO,CAAC,OAAO,CAAgB;IAE/B,2GAA2G;YAC7F,GAAG;IAoBjB,OAAO,CAAC,OAAO;IAiBf,OAAO,CAAC,OAAO;IAUf,gFAAgF;IAChF,OAAO,CAAC,MAAM;CAMf"}
|