nsa-sheets-db-builder 4.0.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/LICENSE +21 -0
- package/README.md +188 -0
- package/bin/sheets-deployer.mjs +169 -0
- package/libs/alasql.js +15577 -0
- package/libs/common/gas_response_helper.ts +147 -0
- package/libs/common/gaserror.ts +101 -0
- package/libs/common/gaslogger.ts +172 -0
- package/libs/db_ddl.ts +316 -0
- package/libs/libraries.json +56 -0
- package/libs/spreadsheets_db.ts +4406 -0
- package/libs/triggers.ts +113 -0
- package/package.json +73 -0
- package/scripts/build.mjs +513 -0
- package/scripts/clean.mjs +31 -0
- package/scripts/create.mjs +94 -0
- package/scripts/ddl-handler.mjs +232 -0
- package/scripts/describe.mjs +38 -0
- package/scripts/drop.mjs +39 -0
- package/scripts/init.mjs +465 -0
- package/scripts/lib/utils.mjs +1019 -0
- package/scripts/login.mjs +102 -0
- package/scripts/provision.mjs +35 -0
- package/scripts/refresh-cache.mjs +34 -0
- package/scripts/set-key.mjs +48 -0
- package/scripts/setup-trigger.mjs +95 -0
- package/scripts/setup.mjs +677 -0
- package/scripts/show.mjs +37 -0
- package/scripts/sync.mjs +35 -0
- package/scripts/whoami.mjs +36 -0
- package/src/api/ddl-handler-entry.ts +136 -0
- package/src/api/ddl.ts +321 -0
- package/src/templates/.clasp.json.ejs +1 -0
- package/src/templates/appsscript.json.ejs +16 -0
- package/src/templates/config.ts.ejs +14 -0
- package/src/templates/ddl-handler-config.ts.ejs +3 -0
- package/src/templates/ddl-handler-main.ts.ejs +56 -0
- package/src/templates/main.ts.ejs +288 -0
- package/src/templates/rbac.ts.ejs +148 -0
- package/src/templates/views.ts.ejs +92 -0
- package/templates/blank.json +33 -0
- package/templates/blog-cms.json +507 -0
- package/templates/crm.json +360 -0
- package/templates/e-commerce.json +424 -0
- package/templates/inventory.json +307 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
class GASStatusV2 {
|
|
2
|
+
type: 'OK' | 'WARNING' | 'ERROR';
|
|
3
|
+
message?: string;
|
|
4
|
+
timestamp: string;
|
|
5
|
+
traceId?: string;
|
|
6
|
+
error?: {
|
|
7
|
+
name: string;
|
|
8
|
+
source: string;
|
|
9
|
+
message: string;
|
|
10
|
+
context?: Record<string, any>;
|
|
11
|
+
originalError?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
constructor(type: 'OK' | 'WARNING' | 'ERROR', message?: string, traceId?: string, error?: any) {
|
|
15
|
+
this.type = type;
|
|
16
|
+
this.timestamp = formatDateTime();
|
|
17
|
+
this.traceId = traceId;
|
|
18
|
+
|
|
19
|
+
// Set message for OK and WARNING types
|
|
20
|
+
if ((type === 'OK' || type === 'WARNING') && message) {
|
|
21
|
+
this.message = message;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Embed error details in status for ERROR type
|
|
25
|
+
if (type === 'ERROR' && error) {
|
|
26
|
+
this.error = error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static OK(message?: string, traceId?: string): GASStatusV2 {
|
|
31
|
+
return new GASStatusV2('OK', message, traceId);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static Warning(message?: string, traceId?: string): GASStatusV2 {
|
|
35
|
+
return new GASStatusV2('WARNING', message, traceId);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static Error(traceId?: string, error?: any): GASStatusV2 {
|
|
39
|
+
return new GASStatusV2('ERROR', undefined, traceId, error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class GASResponseV2 {
|
|
44
|
+
status: GASStatusV2;
|
|
45
|
+
result?: { [key: string]: any };
|
|
46
|
+
|
|
47
|
+
constructor(status: GASStatusV2, result?: { [key: string]: any }) {
|
|
48
|
+
this.status = status;
|
|
49
|
+
|
|
50
|
+
// Only include result for success/warning if provided
|
|
51
|
+
if ((status.type === 'OK' || status.type === 'WARNING') && result !== undefined) {
|
|
52
|
+
this.result = result;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static success(message?: string, result?: { [key: string]: any }, traceId?: string): GASResponseV2 {
|
|
57
|
+
return new GASResponseV2(GASStatusV2.OK(message, traceId), result);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static warning(message?: string, result?: { [key: string]: any }, traceId?: string): GASResponseV2 {
|
|
61
|
+
return new GASResponseV2(GASStatusV2.Warning(message, traceId), result);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static error(error: any): GASResponseV2 {
|
|
65
|
+
let errorObj: any;
|
|
66
|
+
let traceId: string | undefined;
|
|
67
|
+
|
|
68
|
+
if (error && error.name === 'GASErrorV2') {
|
|
69
|
+
traceId = error.traceId;
|
|
70
|
+
errorObj = {
|
|
71
|
+
name: error.name,
|
|
72
|
+
source: error.source,
|
|
73
|
+
message: error.message
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Only include context if not empty
|
|
77
|
+
if (error.context && Object.keys(error.context).length > 0) {
|
|
78
|
+
errorObj.context = error.context;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Only include originalError if it exists and is not empty
|
|
82
|
+
if (error.originalError && error.originalError.trim() !== '') {
|
|
83
|
+
errorObj.originalError = error.originalError;
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
errorObj = {
|
|
87
|
+
name: 'Error',
|
|
88
|
+
source: 'Unknown',
|
|
89
|
+
message: error?.message || error?.toString() || 'Unknown error'
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return new GASResponseV2(GASStatusV2.Error(traceId, errorObj));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
toString(): string {
|
|
97
|
+
return JSON.stringify(this, null, 2);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getTraceId(): string | undefined {
|
|
101
|
+
return this.status.traceId;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
class GASResponseBuilderV2 {
|
|
106
|
+
private traceId?: string;
|
|
107
|
+
private startTime?: number;
|
|
108
|
+
private operationId?: string;
|
|
109
|
+
|
|
110
|
+
constructor(traceId?: string) {
|
|
111
|
+
this.traceId = traceId;
|
|
112
|
+
this.startTime = new Date().getTime();
|
|
113
|
+
this.operationId = Utilities.getUuid();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
setTraceId(traceId: string): this {
|
|
117
|
+
this.traceId = traceId;
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
setOperationId(operationId: string): this {
|
|
122
|
+
this.operationId = operationId;
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
success(message?: string, result?: { [key: string]: any }): GASResponseV2 {
|
|
127
|
+
return GASResponseV2.success(message, result, this.traceId);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
warning(message?: string, result?: { [key: string]: any }): GASResponseV2 {
|
|
131
|
+
return GASResponseV2.warning(message, result, this.traceId);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
error(error: any): GASResponseV2 {
|
|
135
|
+
// Ensure error has traceId set if it's a GASErrorV2
|
|
136
|
+
if (error && error.name === 'GASErrorV2' && !error.traceId && this.traceId) {
|
|
137
|
+
error.setTraceId(this.traceId);
|
|
138
|
+
}
|
|
139
|
+
return GASResponseV2.error(error);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
criticalError(message: string): never {
|
|
143
|
+
throw new Error(message);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export { GASStatusV2, GASResponseV2, GASResponseBuilderV2 };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
class GASErrorV2 extends Error {
|
|
2
|
+
public name: string;
|
|
3
|
+
public source: string;
|
|
4
|
+
public context: Record<string, any>;
|
|
5
|
+
public timestamp: string;
|
|
6
|
+
public traceId: string;
|
|
7
|
+
public originalError: string;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
message: string,
|
|
11
|
+
source: string,
|
|
12
|
+
context: Record<string, any> = {},
|
|
13
|
+
traceId?: string
|
|
14
|
+
) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'GASErrorV2';
|
|
17
|
+
this.message = message;
|
|
18
|
+
this.source = source;
|
|
19
|
+
this.context = context;
|
|
20
|
+
this.timestamp = formatDateTime();
|
|
21
|
+
this.traceId = traceId || '';
|
|
22
|
+
this.originalError = '';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setTraceId(traceId: string): this {
|
|
26
|
+
this.traceId = traceId;
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getTraceId(): string {
|
|
31
|
+
return this.traceId;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static isGASErrorV2(error: any): boolean {
|
|
35
|
+
return error && error.name === 'GASErrorV2';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static handleError(
|
|
39
|
+
error: any,
|
|
40
|
+
message: string,
|
|
41
|
+
source: string,
|
|
42
|
+
context: Record<string, any> = {},
|
|
43
|
+
traceId?: string
|
|
44
|
+
): never {
|
|
45
|
+
throw GASErrorV2.wrapError(error, message, source, context, traceId);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static wrapError(
|
|
49
|
+
error: any,
|
|
50
|
+
message: string,
|
|
51
|
+
source: string,
|
|
52
|
+
context: Record<string, any> = {},
|
|
53
|
+
traceId?: string
|
|
54
|
+
): GASErrorV2 {
|
|
55
|
+
const newError = new GASErrorV2(message, source, context, traceId);
|
|
56
|
+
|
|
57
|
+
if (GASErrorV2.isGASErrorV2(error)) {
|
|
58
|
+
newError.originalError = error.message;
|
|
59
|
+
if (!traceId && error.traceId) {
|
|
60
|
+
newError.traceId = error.traceId;
|
|
61
|
+
}
|
|
62
|
+
} else if (error) {
|
|
63
|
+
newError.originalError = error.toString();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return newError;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static fromErrorGASResponseV2(response: any): GASErrorV2 {
|
|
70
|
+
const parsedError = response.error;
|
|
71
|
+
if (parsedError && parsedError.name === 'GASErrorV2' && parsedError.message && parsedError.source) {
|
|
72
|
+
const err = new GASErrorV2(
|
|
73
|
+
parsedError.message,
|
|
74
|
+
parsedError.source,
|
|
75
|
+
parsedError.context || {},
|
|
76
|
+
parsedError.traceId
|
|
77
|
+
);
|
|
78
|
+
err.originalError = parsedError.originalError || '';
|
|
79
|
+
return err;
|
|
80
|
+
}
|
|
81
|
+
throw new GASErrorV2(
|
|
82
|
+
"Invalid GASErrorV2 response",
|
|
83
|
+
"GASErrorV2.fromErrorGASResponseV2",
|
|
84
|
+
{ response }
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
toJson(): string {
|
|
89
|
+
return JSON.stringify({
|
|
90
|
+
name: this.name,
|
|
91
|
+
source: this.source,
|
|
92
|
+
message: this.message,
|
|
93
|
+
context: this.context,
|
|
94
|
+
timestamp: this.timestamp,
|
|
95
|
+
traceId: this.traceId,
|
|
96
|
+
originalError: this.originalError
|
|
97
|
+
}, null, 2);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export default GASErrorV2;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
class GASLoggerV2 {
|
|
2
|
+
private webhookUrl: string | null;
|
|
3
|
+
private verbosityLevel: number;
|
|
4
|
+
private loggerId: string;
|
|
5
|
+
private traceId: string;
|
|
6
|
+
|
|
7
|
+
constructor(loggerId: string, webhookUrl: string | null = null, verbosityLevel: number = 1, traceId: string = '') {
|
|
8
|
+
this.loggerId = loggerId;
|
|
9
|
+
this.webhookUrl = webhookUrl;
|
|
10
|
+
this.verbosityLevel = verbosityLevel;
|
|
11
|
+
this.traceId = traceId;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
setVerbosityLevel(level: number): void {
|
|
15
|
+
this.verbosityLevel = level;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setTraceId(traceId: string): void {
|
|
19
|
+
this.traceId = traceId;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getTraceId(): string {
|
|
23
|
+
return this.traceId;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
error(error: GASErrorV2): void {
|
|
27
|
+
const originalErrorArray = error.originalError ? [error.originalError] : [];
|
|
28
|
+
|
|
29
|
+
this.log('ERROR', error.source, error.message,
|
|
30
|
+
error.context,
|
|
31
|
+
originalErrorArray,
|
|
32
|
+
error.traceId
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
warn(source: string, message: string, context: any = {}, errors: any[] = [], traceId?: string): void {
|
|
37
|
+
this.log('WARNING', source, message, context, errors, traceId);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
info(source: string, message: string, context: any, traceId?: string): void {
|
|
41
|
+
this.log('INFO', source, message, context, [], traceId);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
debug(source: string, message: string, context: any = {}, errors: any[] = [], traceId?: string): void {
|
|
45
|
+
this.log('DEBUG', source, message, context, errors, traceId);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private log(type: 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR', source: string, message: string, context: any = {}, errors: any[] = [], traceId?: string): void {
|
|
49
|
+
|
|
50
|
+
if (
|
|
51
|
+
(this.verbosityLevel === 1 && type === 'ERROR') ||
|
|
52
|
+
(this.verbosityLevel === 2 && (type === 'ERROR' || type === 'WARNING')) ||
|
|
53
|
+
(this.verbosityLevel === 3 && (type === 'ERROR' || type === 'WARNING' || type === 'INFO')) ||
|
|
54
|
+
(this.verbosityLevel === 4)
|
|
55
|
+
) {
|
|
56
|
+
const logId = this.generateLogId();
|
|
57
|
+
const timestamp = formatDateTime();
|
|
58
|
+
const fullSource = `${source}`;
|
|
59
|
+
const effectiveTraceId = traceId || this.traceId;
|
|
60
|
+
|
|
61
|
+
const logEntry: any = {
|
|
62
|
+
type: type,
|
|
63
|
+
source: fullSource,
|
|
64
|
+
message: message,
|
|
65
|
+
timestamp: timestamp,
|
|
66
|
+
logId: logId,
|
|
67
|
+
traceId: effectiveTraceId,
|
|
68
|
+
pipeline: this.loggerId,
|
|
69
|
+
|
|
70
|
+
};
|
|
71
|
+
if (context) {
|
|
72
|
+
logEntry.context = context;
|
|
73
|
+
}
|
|
74
|
+
if (errors) {
|
|
75
|
+
logEntry.errors = errors;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.outputToConsole(type, logEntry);
|
|
79
|
+
|
|
80
|
+
if (type === 'ERROR' && this.webhookUrl) {
|
|
81
|
+
this.sendToChat(logEntry);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private outputToConsole(type: string, logEntry: any): void {
|
|
87
|
+
switch (type) {
|
|
88
|
+
case 'ERROR':
|
|
89
|
+
console.error(JSON.stringify(logEntry, null, 2));
|
|
90
|
+
break;
|
|
91
|
+
case 'WARNING':
|
|
92
|
+
console.warn(logEntry);
|
|
93
|
+
break;
|
|
94
|
+
case 'INFO':
|
|
95
|
+
console.log(logEntry);
|
|
96
|
+
break;
|
|
97
|
+
case 'DEBUG':
|
|
98
|
+
console.log(logEntry);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private sendToChat(logEntry: { [key: string]: any }): void {
|
|
104
|
+
if (!this.webhookUrl) return;
|
|
105
|
+
|
|
106
|
+
const errorIcon = logEntry.type === 'ERROR' ? '❗ ' : '';
|
|
107
|
+
|
|
108
|
+
const jsonCardData: CardData = {
|
|
109
|
+
type: 'json',
|
|
110
|
+
header: `${errorIcon}${logEntry.source}`,
|
|
111
|
+
widgetSpecs: [
|
|
112
|
+
{
|
|
113
|
+
header: 'Error',
|
|
114
|
+
collapsible: false,
|
|
115
|
+
data: {
|
|
116
|
+
'Pipeline': logEntry.pipeline,
|
|
117
|
+
'Message': logEntry.message,
|
|
118
|
+
'Timestamp': logEntry.timestamp,
|
|
119
|
+
'TraceId': logEntry.traceId,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
header: 'Context',
|
|
124
|
+
collapsible: true,
|
|
125
|
+
data: logEntry.context || {},
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
header: 'Error Stack',
|
|
129
|
+
collapsible: true,
|
|
130
|
+
data: logEntry.errors || [],
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
header: 'Logs',
|
|
134
|
+
collapsible: false,
|
|
135
|
+
data: {
|
|
136
|
+
'LogId': logEntry.logId,
|
|
137
|
+
'TraceId': logEntry.traceId,
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const card = CardFactory.createCardSpec(jsonCardData);
|
|
144
|
+
|
|
145
|
+
const payload = {
|
|
146
|
+
cardsV2: [
|
|
147
|
+
{
|
|
148
|
+
cardId: 'errorCard',
|
|
149
|
+
card: card,
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const chatService = new GoogleChatService(this.webhookUrl);
|
|
155
|
+
chatService.sendMessage(JSON.stringify(payload));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private generateLogId(): string {
|
|
159
|
+
return Utilities.getUuid();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
createChildLogger(traceId?: string): GASLoggerV2 {
|
|
163
|
+
return new GASLoggerV2(
|
|
164
|
+
this.loggerId,
|
|
165
|
+
this.webhookUrl,
|
|
166
|
+
this.verbosityLevel,
|
|
167
|
+
traceId || this.traceId
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export default GASLoggerV2;
|