@cellaware/utils 8.11.19 → 8.11.21
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/azure/cosmos.d.ts +112 -0
- package/dist/azure/cosmos.js +305 -0
- package/dist/azure/email.d.ts +3 -0
- package/dist/azure/email.js +20 -0
- package/dist/azure/function.d.ts +14 -0
- package/dist/azure/function.js +124 -0
- package/dist/azure/slot.d.ts +1 -0
- package/dist/azure/slot.js +4 -0
- package/dist/azure/storage.d.ts +14 -0
- package/dist/azure/storage.js +81 -0
- package/dist/chatwms/alert.d.ts +97 -0
- package/dist/chatwms/alert.js +74 -0
- package/dist/chatwms/azure/cosmos.d.ts +25 -0
- package/dist/chatwms/azure/cosmos.js +43 -0
- package/dist/chatwms/azure/function.d.ts +21 -0
- package/dist/chatwms/azure/function.js +29 -0
- package/dist/chatwms/azure/storage.d.ts +15 -0
- package/dist/chatwms/azure/storage.js +27 -0
- package/dist/chatwms/client.d.ts +18 -0
- package/dist/chatwms/client.js +48 -0
- package/dist/chatwms/cosmos.d.ts +24 -0
- package/dist/chatwms/cosmos.js +532 -0
- package/dist/chatwms/dashboard.d.ts +80 -0
- package/dist/chatwms/dashboard.js +17 -0
- package/dist/chatwms/datagrid.d.ts +215 -0
- package/dist/chatwms/datagrid.js +1459 -0
- package/dist/chatwms/developer.d.ts +27 -0
- package/dist/chatwms/developer.js +12 -0
- package/dist/chatwms/github/issue.d.ts +1 -0
- package/dist/chatwms/github/issue.js +4 -0
- package/dist/chatwms/instance.d.ts +16 -0
- package/dist/chatwms/instance.js +18 -0
- package/dist/chatwms/integration.d.ts +24 -0
- package/dist/chatwms/integration.js +19 -0
- package/dist/chatwms/pdf.d.ts +95 -0
- package/dist/chatwms/pdf.js +147 -0
- package/dist/chatwms/report.d.ts +126 -0
- package/dist/chatwms/report.js +55 -0
- package/dist/chatwms/response.d.ts +18 -0
- package/dist/chatwms/response.js +25 -0
- package/dist/chatwms/search.d.ts +12 -0
- package/dist/chatwms/search.js +9 -0
- package/dist/chatwms/teams.d.ts +237 -0
- package/dist/chatwms/teams.js +205 -0
- package/dist/chatwms/user.d.ts +31 -0
- package/dist/chatwms/user.js +42 -0
- package/dist/chatwms/warehouse.d.ts +3 -0
- package/dist/chatwms/warehouse.js +3 -0
- package/dist/github/issue.d.ts +1 -0
- package/dist/github/issue.js +23 -0
- package/dist/llm/chain-store.d.ts +49 -0
- package/dist/llm/chain-store.js +284 -0
- package/dist/llm/cost.d.ts +3 -0
- package/dist/llm/cost.js +42 -0
- package/dist/llm/model.d.ts +12 -0
- package/dist/llm/model.js +1 -0
- package/dist/stopwatch.d.ts +8 -0
- package/dist/stopwatch.js +36 -0
- package/dist/util.d.ts +45 -0
- package/dist/util.js +288 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +12 -0
- package/package.json +1 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the current date time
|
|
3
|
+
*
|
|
4
|
+
* NOTE: default time zone is UTC
|
|
5
|
+
*/
|
|
6
|
+
export declare function getCosmosCurrentDateTime(timeZone?: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Returns the record's date time using the `_ts` field
|
|
9
|
+
*
|
|
10
|
+
* NOTE: default time zone is UTC
|
|
11
|
+
*/
|
|
12
|
+
export declare function getCosmosTimestampDateTime(timeZone?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Returns the current year
|
|
15
|
+
*
|
|
16
|
+
* NOTE: default time zone is UTC
|
|
17
|
+
*/
|
|
18
|
+
export declare function getCosmosCurrentYear(timeZone?: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the record's year using the `_ts` field
|
|
21
|
+
*
|
|
22
|
+
* NOTE: default time zone is UTC
|
|
23
|
+
*/
|
|
24
|
+
export declare function getCosmosTimestampYear(timeZone?: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Returns the current month
|
|
27
|
+
*
|
|
28
|
+
* NOTE: default time zone is UTC
|
|
29
|
+
*/
|
|
30
|
+
export declare function getCosmosCurrentMonth(timeZone?: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Returns the record's month using the `_ts` field
|
|
33
|
+
*
|
|
34
|
+
* NOTE: default time zone is UTC
|
|
35
|
+
*/
|
|
36
|
+
export declare function getCosmosTimestampMonth(timeZone?: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Returns the current day
|
|
39
|
+
*
|
|
40
|
+
* NOTE: default time zone is UTC
|
|
41
|
+
*/
|
|
42
|
+
export declare function getCosmosCurrentDay(timeZone?: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* Returns the record's day using the `_ts` field
|
|
45
|
+
*
|
|
46
|
+
* NOTE: default time zone is UTC
|
|
47
|
+
*/
|
|
48
|
+
export declare function getCosmosTimestampDay(timeZone?: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Returns the record's hour using the `_ts` field
|
|
51
|
+
*
|
|
52
|
+
* NOTE: default time zone is UTC
|
|
53
|
+
*/
|
|
54
|
+
export declare function getCosmosTimestampHour(timeZone?: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Returns the record's minute using the `_ts` field
|
|
57
|
+
*
|
|
58
|
+
* NOTE: default time zone is UTC
|
|
59
|
+
*/
|
|
60
|
+
export declare function getCosmosTimestampMinute(timeZone?: string): string;
|
|
61
|
+
/**
|
|
62
|
+
* Returns the record's second using the `_ts` field
|
|
63
|
+
*
|
|
64
|
+
* NOTE: default time zone is UTC
|
|
65
|
+
*/
|
|
66
|
+
export declare function getCosmosTimestampSecond(timeZone?: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Returns a `WHERE` clause condition to retrieve records with a `_ts` of today
|
|
69
|
+
*
|
|
70
|
+
* NOTE: default time zone is UTC
|
|
71
|
+
*/
|
|
72
|
+
export declare function getCosmosCurrentDayClause(timeZone?: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Returns a `WHERE` clause condition to retrieve records with a `_ts` of this month
|
|
75
|
+
*
|
|
76
|
+
* NOTE: default time zone is UTC
|
|
77
|
+
*/
|
|
78
|
+
export declare function getCosmosCurrentMonthClause(timeZone?: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* Returns a `WHERE` clause condition to retrieve records with a `_ts` of this year
|
|
81
|
+
*
|
|
82
|
+
* NOTE: default time zone is UTC
|
|
83
|
+
*/
|
|
84
|
+
export declare function getCosmosCurrentYearClause(timeZone?: string): string;
|
|
85
|
+
export declare function _cosmosSelect(endpoint: string, key: string, databaseId: string, collectionId: string, partitionKey: string, query: string): Promise<any[]>;
|
|
86
|
+
export declare function cosmosSelect(databaseId: string, collectionId: string, partitionKey: string, query: string): Promise<any[]>;
|
|
87
|
+
export declare function _cosmosInsert(endpoint: string, key: string, databaseId: string, collectionId: string, partitionKey: string, data: any): Promise<boolean>;
|
|
88
|
+
export declare function cosmosInsert(databaseId: string, collectionId: string, partitionKey: string, data: any): Promise<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* Will delete **multiple** records if `query` returns multiple rows.
|
|
91
|
+
*/
|
|
92
|
+
export declare function _cosmosDelete(endpoint: string, key: string, databaseId: string, collectionId: string, partitionKey: string, query: string): Promise<boolean>;
|
|
93
|
+
/**
|
|
94
|
+
* Will delete **multiple** records if `query` returns multiple rows.
|
|
95
|
+
*/
|
|
96
|
+
export declare function cosmosDelete(databaseId: string, collectionId: string, partitionKey: string, query: string): Promise<boolean>;
|
|
97
|
+
/**
|
|
98
|
+
* Will only update a **single** record. If multiple records are returned from `query`, we will only update the first one.
|
|
99
|
+
*/
|
|
100
|
+
export declare function _cosmosUpdate(endpoint: string, key: string, databaseId: string, collectionId: string, partitionKey: string, query: string, data: any): Promise<boolean>;
|
|
101
|
+
/**
|
|
102
|
+
* Will only update a **single** record. If multiple records are returned from `query`, we will only update the first one.
|
|
103
|
+
*/
|
|
104
|
+
export declare function cosmosUpdate(databaseId: string, collectionId: string, partitionKey: string, query: string, data: any): Promise<boolean>;
|
|
105
|
+
/**
|
|
106
|
+
* Simply deletes an existing record(s) then inserts a new one.
|
|
107
|
+
*/
|
|
108
|
+
export declare function _cosmosUpsert(endpoint: string, key: string, databaseId: string, collectionId: string, partitionKey: string, query: string, data: any): Promise<boolean>;
|
|
109
|
+
/**
|
|
110
|
+
* Simply deletes an existing record(s) then inserts a new one.
|
|
111
|
+
*/
|
|
112
|
+
export declare function cosmosUpsert(databaseId: string, collectionId: string, partitionKey: string, query: string, data: any): Promise<boolean>;
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { ConnectionMode, CosmosClient } from '@azure/cosmos';
|
|
2
|
+
import { isDaylightSavingTime } from '../util.js';
|
|
3
|
+
const COSMOS_CURRENT_DATETIME = `GetCurrentDateTime()`;
|
|
4
|
+
const COSMOS_TIMESTAMP_DATETIME = `TimestampToDateTime(c._ts*1000)`;
|
|
5
|
+
/**
|
|
6
|
+
* All Cosmos timestamps are UTC.
|
|
7
|
+
* https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
|
8
|
+
*/
|
|
9
|
+
const TIME_ZONE_OFFSETS = {
|
|
10
|
+
// North America:
|
|
11
|
+
'America/New_York': -5, 'America/New_York_DST': -4, // Eastern
|
|
12
|
+
'America/Chicago': -6, 'America/Chicago_DST': -5, // Central
|
|
13
|
+
'America/Denver': -7, 'America/Denver_DST': -6, // Mountain
|
|
14
|
+
'America/Phoenix': -7, // Mountain (no DST)
|
|
15
|
+
'America/Los_Angeles': -8, 'America/Los_Angeles_DST': -7, // Pacific
|
|
16
|
+
'America/Anchorage': -9, 'America/Anchorage_DST': -8, // Alaska
|
|
17
|
+
'Pacific/Honolulu': -10, // Hawaii (no DST)
|
|
18
|
+
// South America:
|
|
19
|
+
'America/Sao_Paulo': -3, // Brazil (DST mostly abolished)
|
|
20
|
+
'America/Buenos_Aires': -3, // Argentina
|
|
21
|
+
// Europe:
|
|
22
|
+
'Europe/London': 0, 'Europe/London_DST': 1, // UK
|
|
23
|
+
'Europe/Berlin': 1, 'Europe/Berlin_DST': 2, // Central Europe
|
|
24
|
+
'Europe/Moscow': 3, // Russia (no DST)
|
|
25
|
+
// Asia:
|
|
26
|
+
'Asia/Dubai': 4, // UAE
|
|
27
|
+
'Asia/Kolkata': 5.5, // India
|
|
28
|
+
'Asia/Shanghai': 8, // China
|
|
29
|
+
'Asia/Tokyo': 9, // Japan
|
|
30
|
+
'Asia/Singapore': 8,
|
|
31
|
+
// Australia:
|
|
32
|
+
'Australia/Sydney': 10, 'Australia/Sydney_DST': 11,
|
|
33
|
+
'Australia/Perth': 8,
|
|
34
|
+
// Africa:
|
|
35
|
+
'Africa/Johannesburg': 2,
|
|
36
|
+
'Africa/Lagos': 1
|
|
37
|
+
};
|
|
38
|
+
function getCosmosTimeZoneHourDiff(timeZone) {
|
|
39
|
+
let diff = 0;
|
|
40
|
+
if (!!timeZone) {
|
|
41
|
+
let lookupTimeZone = timeZone;
|
|
42
|
+
if (isDaylightSavingTime(timeZone)) {
|
|
43
|
+
lookupTimeZone += '_DST';
|
|
44
|
+
}
|
|
45
|
+
if (lookupTimeZone in TIME_ZONE_OFFSETS) {
|
|
46
|
+
diff = TIME_ZONE_OFFSETS[lookupTimeZone];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return diff;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the current date time
|
|
53
|
+
*
|
|
54
|
+
* NOTE: default time zone is UTC
|
|
55
|
+
*/
|
|
56
|
+
export function getCosmosCurrentDateTime(timeZone) {
|
|
57
|
+
return `DateTimeAdd("hh", ${getCosmosTimeZoneHourDiff(timeZone)}, ${COSMOS_CURRENT_DATETIME})`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns the record's date time using the `_ts` field
|
|
61
|
+
*
|
|
62
|
+
* NOTE: default time zone is UTC
|
|
63
|
+
*/
|
|
64
|
+
export function getCosmosTimestampDateTime(timeZone) {
|
|
65
|
+
return `DateTimeAdd("hh", ${getCosmosTimeZoneHourDiff(timeZone)}, ${COSMOS_TIMESTAMP_DATETIME})`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Returns the current year
|
|
69
|
+
*
|
|
70
|
+
* NOTE: default time zone is UTC
|
|
71
|
+
*/
|
|
72
|
+
export function getCosmosCurrentYear(timeZone) {
|
|
73
|
+
return `DateTimePart('yyyy', ${getCosmosCurrentDateTime(timeZone)})`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Returns the record's year using the `_ts` field
|
|
77
|
+
*
|
|
78
|
+
* NOTE: default time zone is UTC
|
|
79
|
+
*/
|
|
80
|
+
export function getCosmosTimestampYear(timeZone) {
|
|
81
|
+
return `DateTimePart('yyyy', ${getCosmosTimestampDateTime(timeZone)})`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Returns the current month
|
|
85
|
+
*
|
|
86
|
+
* NOTE: default time zone is UTC
|
|
87
|
+
*/
|
|
88
|
+
export function getCosmosCurrentMonth(timeZone) {
|
|
89
|
+
return `DateTimePart('mm', ${getCosmosCurrentDateTime(timeZone)})`;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Returns the record's month using the `_ts` field
|
|
93
|
+
*
|
|
94
|
+
* NOTE: default time zone is UTC
|
|
95
|
+
*/
|
|
96
|
+
export function getCosmosTimestampMonth(timeZone) {
|
|
97
|
+
return `DateTimePart('mm', ${getCosmosTimestampDateTime(timeZone)})`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Returns the current day
|
|
101
|
+
*
|
|
102
|
+
* NOTE: default time zone is UTC
|
|
103
|
+
*/
|
|
104
|
+
export function getCosmosCurrentDay(timeZone) {
|
|
105
|
+
return `DateTimePart('dd', ${getCosmosCurrentDateTime(timeZone)})`;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Returns the record's day using the `_ts` field
|
|
109
|
+
*
|
|
110
|
+
* NOTE: default time zone is UTC
|
|
111
|
+
*/
|
|
112
|
+
export function getCosmosTimestampDay(timeZone) {
|
|
113
|
+
return `DateTimePart('dd', ${getCosmosTimestampDateTime(timeZone)})`;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Returns the record's hour using the `_ts` field
|
|
117
|
+
*
|
|
118
|
+
* NOTE: default time zone is UTC
|
|
119
|
+
*/
|
|
120
|
+
export function getCosmosTimestampHour(timeZone) {
|
|
121
|
+
return `DateTimePart('hh', ${getCosmosTimestampDateTime(timeZone)})`;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Returns the record's minute using the `_ts` field
|
|
125
|
+
*
|
|
126
|
+
* NOTE: default time zone is UTC
|
|
127
|
+
*/
|
|
128
|
+
export function getCosmosTimestampMinute(timeZone) {
|
|
129
|
+
return `DateTimePart('mi', ${getCosmosTimestampDateTime(timeZone)})`;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Returns the record's second using the `_ts` field
|
|
133
|
+
*
|
|
134
|
+
* NOTE: default time zone is UTC
|
|
135
|
+
*/
|
|
136
|
+
export function getCosmosTimestampSecond(timeZone) {
|
|
137
|
+
return `DateTimePart('ss', ${getCosmosTimestampDateTime(timeZone)})`;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Returns a `WHERE` clause condition to retrieve records with a `_ts` of today
|
|
141
|
+
*
|
|
142
|
+
* NOTE: default time zone is UTC
|
|
143
|
+
*/
|
|
144
|
+
export function getCosmosCurrentDayClause(timeZone) {
|
|
145
|
+
return `DateTimeDiff('dd', ${getCosmosTimestampDateTime(timeZone)}, ${getCosmosCurrentDateTime(timeZone)}) = 0`;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Returns a `WHERE` clause condition to retrieve records with a `_ts` of this month
|
|
149
|
+
*
|
|
150
|
+
* NOTE: default time zone is UTC
|
|
151
|
+
*/
|
|
152
|
+
export function getCosmosCurrentMonthClause(timeZone) {
|
|
153
|
+
return `DateTimeDiff('mm', ${getCosmosTimestampDateTime(timeZone)}, ${getCosmosCurrentDateTime(timeZone)}) = 0`;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Returns a `WHERE` clause condition to retrieve records with a `_ts` of this year
|
|
157
|
+
*
|
|
158
|
+
* NOTE: default time zone is UTC
|
|
159
|
+
*/
|
|
160
|
+
export function getCosmosCurrentYearClause(timeZone) {
|
|
161
|
+
return `DateTimeDiff('yyyy', ${getCosmosTimestampDateTime(timeZone)}, ${getCosmosCurrentDateTime(timeZone)}) = 0`;
|
|
162
|
+
}
|
|
163
|
+
export async function _cosmosSelect(endpoint, key, databaseId, collectionId, partitionKey, query) {
|
|
164
|
+
try {
|
|
165
|
+
const cosmosClient = new CosmosClient({
|
|
166
|
+
endpoint,
|
|
167
|
+
key,
|
|
168
|
+
connectionPolicy: { connectionMode: ConnectionMode.Gateway, enableEndpointDiscovery: false }
|
|
169
|
+
});
|
|
170
|
+
const { database } = await cosmosClient.databases.createIfNotExists({ id: databaseId });
|
|
171
|
+
const { container } = await database.containers.createIfNotExists({
|
|
172
|
+
id: collectionId,
|
|
173
|
+
partitionKey
|
|
174
|
+
});
|
|
175
|
+
const { resources } = await container.items.query({ query }).fetchAll();
|
|
176
|
+
return resources;
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
throw new Error(`COSMOS: Select error: ${err.message}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
export async function cosmosSelect(databaseId, collectionId, partitionKey, query) {
|
|
183
|
+
return _cosmosSelect(process.env.COSMOS_DB_ENDPOINT ?? '', process.env.COSMOS_DB_KEY ?? '', databaseId, collectionId, partitionKey, query);
|
|
184
|
+
}
|
|
185
|
+
export async function _cosmosInsert(endpoint, key, databaseId, collectionId, partitionKey, data) {
|
|
186
|
+
try {
|
|
187
|
+
const cosmosClient = new CosmosClient({
|
|
188
|
+
endpoint,
|
|
189
|
+
key,
|
|
190
|
+
connectionPolicy: { connectionMode: ConnectionMode.Gateway, enableEndpointDiscovery: false }
|
|
191
|
+
});
|
|
192
|
+
const { database } = await cosmosClient.databases.createIfNotExists({ id: databaseId });
|
|
193
|
+
const { container } = await database.containers.createIfNotExists({
|
|
194
|
+
id: collectionId,
|
|
195
|
+
partitionKey
|
|
196
|
+
});
|
|
197
|
+
await container.items.create(data);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
throw new Error(`COSMOS: Insert error: ${err.message}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
export async function cosmosInsert(databaseId, collectionId, partitionKey, data) {
|
|
205
|
+
return _cosmosInsert(process.env.COSMOS_DB_ENDPOINT ?? '', process.env.COSMOS_DB_KEY ?? '', databaseId, collectionId, partitionKey, data);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Will delete **multiple** records if `query` returns multiple rows.
|
|
209
|
+
*/
|
|
210
|
+
export async function _cosmosDelete(endpoint, key, databaseId, collectionId, partitionKey, query) {
|
|
211
|
+
try {
|
|
212
|
+
const cosmosClient = new CosmosClient({
|
|
213
|
+
endpoint,
|
|
214
|
+
key,
|
|
215
|
+
connectionPolicy: { connectionMode: ConnectionMode.Gateway, enableEndpointDiscovery: false }
|
|
216
|
+
});
|
|
217
|
+
const { database } = await cosmosClient.databases.createIfNotExists({ id: databaseId });
|
|
218
|
+
const { container } = await database.containers.createIfNotExists({
|
|
219
|
+
id: collectionId,
|
|
220
|
+
partitionKey
|
|
221
|
+
});
|
|
222
|
+
const { resources } = await container.items.query({ query }).fetchAll();
|
|
223
|
+
// NOTE: need to remove the '/' at the beginning.
|
|
224
|
+
const partitionKeyColumn = partitionKey.startsWith('/') ? partitionKey.substring(1) : partitionKey;
|
|
225
|
+
resources.forEach(doc => {
|
|
226
|
+
container.item(doc.id, doc[partitionKeyColumn]).delete();
|
|
227
|
+
});
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
throw new Error(`COSMOS: Delete error: ${err.message}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Will delete **multiple** records if `query` returns multiple rows.
|
|
236
|
+
*/
|
|
237
|
+
export async function cosmosDelete(databaseId, collectionId, partitionKey, query) {
|
|
238
|
+
return _cosmosDelete(process.env.COSMOS_DB_ENDPOINT ?? '', process.env.COSMOS_DB_KEY ?? '', databaseId, collectionId, partitionKey, query);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Will only update a **single** record. If multiple records are returned from `query`, we will only update the first one.
|
|
242
|
+
*/
|
|
243
|
+
export async function _cosmosUpdate(endpoint, key, databaseId, collectionId, partitionKey, query, data) {
|
|
244
|
+
try {
|
|
245
|
+
if (Array.isArray(data)) {
|
|
246
|
+
throw new Error('COSMOS: Input `data` cannot be an array');
|
|
247
|
+
}
|
|
248
|
+
const cosmosClient = new CosmosClient({
|
|
249
|
+
endpoint,
|
|
250
|
+
key,
|
|
251
|
+
connectionPolicy: { connectionMode: ConnectionMode.Gateway, enableEndpointDiscovery: false }
|
|
252
|
+
});
|
|
253
|
+
const { database } = await cosmosClient.databases.createIfNotExists({ id: databaseId });
|
|
254
|
+
const { container } = await database.containers.createIfNotExists({
|
|
255
|
+
id: collectionId,
|
|
256
|
+
partitionKey
|
|
257
|
+
});
|
|
258
|
+
const { resources } = await container.items.query({ query }).fetchAll();
|
|
259
|
+
// NOTE: need to remove the '/' at the beginning.
|
|
260
|
+
const partitionKeyColumn = partitionKey.startsWith('/') ? partitionKey.substring(1) : partitionKey;
|
|
261
|
+
if (resources.length > 0) {
|
|
262
|
+
const doc = resources[0];
|
|
263
|
+
// Data needs original `id` and partition key field.
|
|
264
|
+
data.id = doc.id;
|
|
265
|
+
data[partitionKeyColumn] = doc[partitionKeyColumn];
|
|
266
|
+
await container.item(doc.id, doc[partitionKeyColumn]).replace(data);
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
console.log(`COSMOS: Update warning: No data found`);
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
throw new Error(`COSMOS: Update error: ${err.message}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Will only update a **single** record. If multiple records are returned from `query`, we will only update the first one.
|
|
280
|
+
*/
|
|
281
|
+
export async function cosmosUpdate(databaseId, collectionId, partitionKey, query, data) {
|
|
282
|
+
return _cosmosUpdate(process.env.COSMOS_DB_ENDPOINT ?? '', process.env.COSMOS_DB_KEY ?? '', databaseId, collectionId, partitionKey, query, data);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Simply deletes an existing record(s) then inserts a new one.
|
|
286
|
+
*/
|
|
287
|
+
export async function _cosmosUpsert(endpoint, key, databaseId, collectionId, partitionKey, query, data) {
|
|
288
|
+
const delRes = await _cosmosDelete(endpoint, key, databaseId, collectionId, partitionKey, query);
|
|
289
|
+
if (!delRes) {
|
|
290
|
+
return delRes;
|
|
291
|
+
}
|
|
292
|
+
const insRes = await _cosmosInsert(endpoint, key, databaseId, collectionId, partitionKey, data);
|
|
293
|
+
return insRes;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Simply deletes an existing record(s) then inserts a new one.
|
|
297
|
+
*/
|
|
298
|
+
export async function cosmosUpsert(databaseId, collectionId, partitionKey, query, data) {
|
|
299
|
+
const delRes = await cosmosDelete(databaseId, collectionId, partitionKey, query);
|
|
300
|
+
if (!delRes) {
|
|
301
|
+
return delRes;
|
|
302
|
+
}
|
|
303
|
+
const insRes = await cosmosInsert(databaseId, collectionId, partitionKey, data);
|
|
304
|
+
return insRes;
|
|
305
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { EmailAttachment, EmailClient, EmailContent } from "@azure/communication-email";
|
|
2
|
+
export declare function initEmailClient(): EmailClient;
|
|
3
|
+
export declare function emailSend(client: EmailClient, senderAddress: string, recipients: string[], content: EmailContent, attachments?: EmailAttachment[]): Promise<import("@azure/core-lro").PollerLike<import("@azure/core-lro").PollOperationState<import("@azure/communication-email").EmailSendResponse>, import("@azure/communication-email").EmailSendResponse>>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EmailClient } from "@azure/communication-email";
|
|
2
|
+
export function initEmailClient() {
|
|
3
|
+
return new EmailClient(process.env.COMMUNICATION_SERVICES_CONNECTION_STRING ?? '');
|
|
4
|
+
}
|
|
5
|
+
export async function emailSend(client, senderAddress, recipients, content, attachments) {
|
|
6
|
+
const message = {
|
|
7
|
+
senderAddress,
|
|
8
|
+
content,
|
|
9
|
+
recipients: {
|
|
10
|
+
to: recipients.map(address => {
|
|
11
|
+
return {
|
|
12
|
+
address,
|
|
13
|
+
displayName: "Recipient",
|
|
14
|
+
};
|
|
15
|
+
}),
|
|
16
|
+
},
|
|
17
|
+
attachments
|
|
18
|
+
};
|
|
19
|
+
return client.beginSend(message);
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Readable } from "stream";
|
|
2
|
+
export declare const AZURE_HEADER_FUNCTION_KEY = "x-functions-key";
|
|
3
|
+
export declare const AZURE_HEADER_PRINCIPAL = "x-ms-client-principal";
|
|
4
|
+
export declare function functionFetchJson(url: string, method: string, key: string, principal: string, body?: any): Promise<Response>;
|
|
5
|
+
export declare function functionFetchJsonWithText(url: string, method: string, key: string, principal: string, text: string): Promise<Response>;
|
|
6
|
+
export declare function functionFetchText(url: string, method: string, key: string, principal: string, body?: any): Promise<Response>;
|
|
7
|
+
export declare function functionStreamJson(url: string, method: string, key: string, principal: string, body: any, errorBody: any): Promise<{
|
|
8
|
+
headers: {
|
|
9
|
+
"Content-Type": string;
|
|
10
|
+
"Cache-Control": string;
|
|
11
|
+
"Transfer-Encoding": string;
|
|
12
|
+
};
|
|
13
|
+
body: Readable;
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Readable } from "stream";
|
|
2
|
+
import { sleep } from "../util.js";
|
|
3
|
+
export const AZURE_HEADER_FUNCTION_KEY = 'x-functions-key';
|
|
4
|
+
export const AZURE_HEADER_PRINCIPAL = 'x-ms-client-principal';
|
|
5
|
+
const STATUS_INTERNAL_SERVER_ERROR = 500;
|
|
6
|
+
const STATUS_SERVICE_UNAVAILABLE = 503;
|
|
7
|
+
const RETRY_SLEEP_MS = 3000;
|
|
8
|
+
const MAX_RETRIES = 3;
|
|
9
|
+
async function functionFetch(url, req) {
|
|
10
|
+
let res = new Response(null, { status: STATUS_SERVICE_UNAVAILABLE, statusText: 'Service Unavailable' });
|
|
11
|
+
let retryNum = 0;
|
|
12
|
+
do {
|
|
13
|
+
if (retryNum > 0) {
|
|
14
|
+
await sleep(RETRY_SLEEP_MS);
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
res = await fetch(url, req);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
// if at max retries throw the error
|
|
21
|
+
if (retryNum === MAX_RETRIES) {
|
|
22
|
+
throw err;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
retryNum++;
|
|
26
|
+
} while (retryNum < MAX_RETRIES &&
|
|
27
|
+
(res.status === STATUS_INTERNAL_SERVER_ERROR || res.status === STATUS_SERVICE_UNAVAILABLE));
|
|
28
|
+
return res;
|
|
29
|
+
}
|
|
30
|
+
async function functionStream(url, req, errorBody) {
|
|
31
|
+
let stream = new Readable();
|
|
32
|
+
stream._read = () => { };
|
|
33
|
+
fetch(url, req)
|
|
34
|
+
.then(async (res) => {
|
|
35
|
+
const body = res.body;
|
|
36
|
+
if (!!body) {
|
|
37
|
+
const reader = body.getReader();
|
|
38
|
+
let streamDone = false;
|
|
39
|
+
while (!streamDone) {
|
|
40
|
+
const { value, done } = await reader.read();
|
|
41
|
+
streamDone = done;
|
|
42
|
+
if (!!value) {
|
|
43
|
+
const buf = Buffer.from(value);
|
|
44
|
+
stream.push(buf.toString());
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
stream.push(null);
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
.catch(err => {
|
|
51
|
+
stream.push(JSON.stringify(errorBody));
|
|
52
|
+
stream.push(null);
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
headers: {
|
|
56
|
+
"Content-Type": "text/event-stream",
|
|
57
|
+
"Cache-Control": "no-cache",
|
|
58
|
+
"Transfer-Encoding": "chunked"
|
|
59
|
+
},
|
|
60
|
+
body: stream
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export async function functionFetchJson(url, method, key, principal, body) {
|
|
64
|
+
const headers = {
|
|
65
|
+
'Content-Type': 'application/json',
|
|
66
|
+
'Accept': 'application/json',
|
|
67
|
+
'x-functions-key': key,
|
|
68
|
+
'x-ms-client-principal': principal
|
|
69
|
+
};
|
|
70
|
+
let req = {
|
|
71
|
+
method,
|
|
72
|
+
headers
|
|
73
|
+
};
|
|
74
|
+
if (body != null) {
|
|
75
|
+
req.body = JSON.stringify(body);
|
|
76
|
+
}
|
|
77
|
+
return functionFetch(url, req);
|
|
78
|
+
}
|
|
79
|
+
export async function functionFetchJsonWithText(url, method, key, principal, text) {
|
|
80
|
+
const headers = {
|
|
81
|
+
'Content-Type': 'application/json',
|
|
82
|
+
'Accept': 'application/json',
|
|
83
|
+
'x-functions-key': key,
|
|
84
|
+
'x-ms-client-principal': principal
|
|
85
|
+
};
|
|
86
|
+
let req = {
|
|
87
|
+
method,
|
|
88
|
+
headers,
|
|
89
|
+
body: text
|
|
90
|
+
};
|
|
91
|
+
return functionFetch(url, req);
|
|
92
|
+
}
|
|
93
|
+
export async function functionFetchText(url, method, key, principal, body) {
|
|
94
|
+
const headers = {
|
|
95
|
+
'Content-Type': 'application/json',
|
|
96
|
+
'Accept': 'application/text',
|
|
97
|
+
'x-functions-key': key,
|
|
98
|
+
'x-ms-client-principal': principal
|
|
99
|
+
};
|
|
100
|
+
let req = {
|
|
101
|
+
method,
|
|
102
|
+
headers
|
|
103
|
+
};
|
|
104
|
+
if (body != null) {
|
|
105
|
+
req.body = JSON.stringify(body);
|
|
106
|
+
}
|
|
107
|
+
return functionFetch(url, req);
|
|
108
|
+
}
|
|
109
|
+
export async function functionStreamJson(url, method, key, principal, body, errorBody) {
|
|
110
|
+
const headers = {
|
|
111
|
+
'Content-Type': 'application/json',
|
|
112
|
+
'Accept': 'text/event-stream',
|
|
113
|
+
'x-functions-key': key,
|
|
114
|
+
'x-ms-client-principal': principal
|
|
115
|
+
};
|
|
116
|
+
let req = {
|
|
117
|
+
method,
|
|
118
|
+
headers
|
|
119
|
+
};
|
|
120
|
+
if (body != null) {
|
|
121
|
+
req.body = JSON.stringify(body);
|
|
122
|
+
}
|
|
123
|
+
return functionStream(url, req, errorBody);
|
|
124
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function slotIsProduction(): boolean;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function storageContainerCreate(containerClientId: string): Promise<void>;
|
|
2
|
+
/**
|
|
3
|
+
* Stringifies `data` and uploads to blob storage.
|
|
4
|
+
*
|
|
5
|
+
* **Important:** `data` must not be a string.
|
|
6
|
+
*/
|
|
7
|
+
export declare function storageBlobUpload(containerClientId: string, blobId: string, data: any): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Parses string data downloaded from blob storage and returns JSON object/JSON array.
|
|
10
|
+
*
|
|
11
|
+
* **Important:** will return `undefined` if any issues or blob does not exist.
|
|
12
|
+
*/
|
|
13
|
+
export declare function storageBlobDownload(containerClientId: string, blobId: string): Promise<any>;
|
|
14
|
+
export declare function storageBlobDelete(containerClientId: string, blobId: string): Promise<void>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { BlobServiceClient } from '@azure/storage-blob';
|
|
2
|
+
function streamToBuffer(stream) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
const chunks = [];
|
|
5
|
+
stream.on("data", (data) => {
|
|
6
|
+
chunks.push(Buffer.isBuffer(data) ? data : Buffer.from(data));
|
|
7
|
+
});
|
|
8
|
+
stream.on("end", () => {
|
|
9
|
+
resolve(Buffer.concat(chunks));
|
|
10
|
+
});
|
|
11
|
+
stream.on("error", reject);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export async function storageContainerCreate(containerClientId) {
|
|
15
|
+
try {
|
|
16
|
+
const blobServiceClient = BlobServiceClient.fromConnectionString(process.env.STORAGE_CONNECTION_STRING ?? '');
|
|
17
|
+
const containerClient = blobServiceClient.getContainerClient(containerClientId);
|
|
18
|
+
await containerClient.create();
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
console.log(`STORAGE: CONTAINER create error: ${err.message}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Stringifies `data` and uploads to blob storage.
|
|
26
|
+
*
|
|
27
|
+
* **Important:** `data` must not be a string.
|
|
28
|
+
*/
|
|
29
|
+
export async function storageBlobUpload(containerClientId, blobId, data) {
|
|
30
|
+
if (typeof data === 'string') {
|
|
31
|
+
throw new Error('STORAGE: Input `data` cannot be a string');
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const blobServiceClient = BlobServiceClient.fromConnectionString(process.env.STORAGE_CONNECTION_STRING ?? '');
|
|
35
|
+
const containerClient = blobServiceClient.getContainerClient(containerClientId);
|
|
36
|
+
const blockBlobClient = containerClient.getBlockBlobClient(blobId);
|
|
37
|
+
const str = JSON.stringify(data);
|
|
38
|
+
await blockBlobClient.upload(str, str.length);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
console.log(`STORAGE: BLOB upload error: ${err.message}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Parses string data downloaded from blob storage and returns JSON object/JSON array.
|
|
46
|
+
*
|
|
47
|
+
* **Important:** will return `undefined` if any issues or blob does not exist.
|
|
48
|
+
*/
|
|
49
|
+
export async function storageBlobDownload(containerClientId, blobId) {
|
|
50
|
+
if (!process.env.STORAGE_CONNECTION_STRING) {
|
|
51
|
+
console.log(`STORAGE: No connection string set`);
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const blobServiceClient = BlobServiceClient.fromConnectionString(process.env.STORAGE_CONNECTION_STRING ?? '');
|
|
56
|
+
const containerClient = blobServiceClient.getContainerClient(containerClientId);
|
|
57
|
+
const blockBlobClient = containerClient.getBlockBlobClient(blobId);
|
|
58
|
+
const downloadBlockBlobResponse = await blockBlobClient.download(0);
|
|
59
|
+
let data;
|
|
60
|
+
if (downloadBlockBlobResponse.readableStreamBody) {
|
|
61
|
+
let buf = await streamToBuffer(downloadBlockBlobResponse.readableStreamBody);
|
|
62
|
+
data = buf.toString();
|
|
63
|
+
}
|
|
64
|
+
return JSON.parse(data);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
console.log(`STORAGE: BLOB download error: ${err.message}`);
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
export async function storageBlobDelete(containerClientId, blobId) {
|
|
72
|
+
try {
|
|
73
|
+
const blobServiceClient = BlobServiceClient.fromConnectionString(process.env.STORAGE_CONNECTION_STRING ?? '');
|
|
74
|
+
const containerClient = blobServiceClient.getContainerClient(containerClientId);
|
|
75
|
+
const blockBlobClient = containerClient.getBlockBlobClient(blobId);
|
|
76
|
+
await blockBlobClient.delete();
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
console.log(`STORAGE: BLOB delete error: ${err.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|