@reddoorla/maintenance 0.6.8 → 0.7.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/README.md +299 -7
- package/dist/cli/bin.js +769 -2
- package/dist/cli/bin.js.map +1 -1
- package/dist/index.d.ts +178 -1
- package/dist/index.js +636 -0
- package/dist/index.js.map +1 -1
- package/package.json +7 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { S as Site, b as AuditResult, a as AuditName, c as RecipeResult, R as RecipeName, I as InventoryProvider } from './sync-configs-pMPW4wTq.js';
|
|
2
2
|
export { C as ConfigName, d as SyncConfigsOptions, s as syncConfigs } from './sync-configs-pMPW4wTq.js';
|
|
3
|
+
import * as airtable_lib_airtable_base_js from 'airtable/lib/airtable_base.js';
|
|
3
4
|
|
|
4
5
|
type SpawnResult = {
|
|
5
6
|
code: number;
|
|
@@ -91,4 +92,180 @@ declare function localPath(path: string, opts?: LocalPathOptions): InventoryProv
|
|
|
91
92
|
|
|
92
93
|
declare function fromJsonFile(path: string): InventoryProvider;
|
|
93
94
|
|
|
94
|
-
|
|
95
|
+
type ReportType = "Maintenance" | "Testing";
|
|
96
|
+
type LighthouseScores = {
|
|
97
|
+
performance: number;
|
|
98
|
+
accessibility: number;
|
|
99
|
+
bestPractices: number;
|
|
100
|
+
seo: number;
|
|
101
|
+
};
|
|
102
|
+
type HeaderImage = {
|
|
103
|
+
/** Stable filename, used as the CID inside the email and as the attachment name in Resend. */
|
|
104
|
+
filename: string;
|
|
105
|
+
/** Bytes of the image, fetched once from Airtable before render+send. */
|
|
106
|
+
bytes: Uint8Array;
|
|
107
|
+
/** MIME, e.g. "image/jpeg". */
|
|
108
|
+
contentType: string;
|
|
109
|
+
};
|
|
110
|
+
/** Everything the template needs to render one report email. */
|
|
111
|
+
type ReportData = {
|
|
112
|
+
siteName: string;
|
|
113
|
+
siteUrl: string;
|
|
114
|
+
reportType: ReportType;
|
|
115
|
+
completedOn: Date;
|
|
116
|
+
lighthouse: LighthouseScores;
|
|
117
|
+
gaUsersCurrent: number;
|
|
118
|
+
gaUsersPrevious: number;
|
|
119
|
+
/** Only used when reportType === "Maintenance"; the date shown next to the blurred-testing image. */
|
|
120
|
+
lastTestedDate: Date | null;
|
|
121
|
+
/** Optional free-text rendered as a section above the footer. */
|
|
122
|
+
commentary: string | null;
|
|
123
|
+
/** Used in the header `mj-image src`; the email attaches the bytes with this CID. */
|
|
124
|
+
headerImageCid: string;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
type AirtableConfig = {
|
|
128
|
+
apiKey: string;
|
|
129
|
+
baseId: string;
|
|
130
|
+
};
|
|
131
|
+
type AirtableBase = ReturnType<typeof openBase>;
|
|
132
|
+
declare function openBase(cfg: AirtableConfig): airtable_lib_airtable_base_js.AirtableBase;
|
|
133
|
+
|
|
134
|
+
type Frequency = "None" | "Monthly" | "Quarterly" | "Yearly";
|
|
135
|
+
type WebsiteRow = {
|
|
136
|
+
id: string;
|
|
137
|
+
name: string;
|
|
138
|
+
url: string;
|
|
139
|
+
pointOfContact: string | null;
|
|
140
|
+
maintenanceFreq: Frequency;
|
|
141
|
+
testingFreq: Frequency;
|
|
142
|
+
/** Last manually-recorded maintenance day (used as fallback when no Reports row exists). */
|
|
143
|
+
maintenanceDay: string | null;
|
|
144
|
+
testingDay: string | null;
|
|
145
|
+
ga4PropertyId: string | null;
|
|
146
|
+
reportRecipientsTo: string | null;
|
|
147
|
+
reportRecipientsCc: string | null;
|
|
148
|
+
/** First attachment in the Header image field (Airtable's signed URL — fetch before expiry). */
|
|
149
|
+
headerImage: {
|
|
150
|
+
url: string;
|
|
151
|
+
filename: string;
|
|
152
|
+
type: string;
|
|
153
|
+
} | null;
|
|
154
|
+
/** Lighthouse "current state" snapshot, manually kept fresh by the operator. */
|
|
155
|
+
pScore: number | null;
|
|
156
|
+
rScore: number | null;
|
|
157
|
+
bpScore: number | null;
|
|
158
|
+
seoScore: number | null;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
type DeliveryStatus = "pending" | "delivered" | "bounced" | "complained";
|
|
162
|
+
type ReportRow = {
|
|
163
|
+
id: string;
|
|
164
|
+
reportId: string;
|
|
165
|
+
siteId: string;
|
|
166
|
+
reportType: ReportType;
|
|
167
|
+
periodStart: string | null;
|
|
168
|
+
periodEnd: string | null;
|
|
169
|
+
completedOn: string | null;
|
|
170
|
+
lighthouse: LighthouseScores | null;
|
|
171
|
+
gaUsersCurrent: number | null;
|
|
172
|
+
gaUsersPrevious: number | null;
|
|
173
|
+
lastTestedDate: string | null;
|
|
174
|
+
commentary: string | null;
|
|
175
|
+
subjectOverride: string | null;
|
|
176
|
+
draftReady: boolean;
|
|
177
|
+
approvedToSend: boolean;
|
|
178
|
+
sentAt: string | null;
|
|
179
|
+
deliveryStatus: DeliveryStatus;
|
|
180
|
+
renderedHtmlAttachment: {
|
|
181
|
+
url: string;
|
|
182
|
+
filename: string;
|
|
183
|
+
} | null;
|
|
184
|
+
/** Read out of the Resend response and stored in a hidden field; needed for webhook reconciliation. */
|
|
185
|
+
resendMessageId: string | null;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
type DraftOptions = {
|
|
189
|
+
/** Where to write the local preview HTML when `previewOnly`. Defaults to `reports/<slug>/draft.html`. */
|
|
190
|
+
previewPath?: string;
|
|
191
|
+
/** If true: render locally only, never touch Airtable. */
|
|
192
|
+
previewOnly?: boolean;
|
|
193
|
+
};
|
|
194
|
+
type DraftResult = {
|
|
195
|
+
/** null when previewOnly. */
|
|
196
|
+
reportRow: ReportRow | null;
|
|
197
|
+
/** Path to the local preview file (only set when previewOnly). */
|
|
198
|
+
htmlPath: string | null;
|
|
199
|
+
/** Always present — the rendered HTML string. */
|
|
200
|
+
html: string;
|
|
201
|
+
};
|
|
202
|
+
declare function draftReportForSite(base: AirtableBase | null, siteRow: WebsiteRow, reportType: ReportType, options?: DraftOptions): Promise<DraftResult>;
|
|
203
|
+
|
|
204
|
+
type ResendSendInput = {
|
|
205
|
+
from: string;
|
|
206
|
+
to: string[];
|
|
207
|
+
cc?: string[];
|
|
208
|
+
replyTo?: string;
|
|
209
|
+
subject: string;
|
|
210
|
+
html: string;
|
|
211
|
+
attachments?: Array<{
|
|
212
|
+
filename: string;
|
|
213
|
+
content: string;
|
|
214
|
+
contentType?: string;
|
|
215
|
+
/** Setting this attaches the file as inline; reference it from HTML as `src="cid:<id>"`. */
|
|
216
|
+
inlineContentId?: string;
|
|
217
|
+
}>;
|
|
218
|
+
/**
|
|
219
|
+
* Stable key forwarded as the `Idempotency-Key` header. Resend dedupes calls
|
|
220
|
+
* with the same key for 24 hours, returning the original message id. Use a
|
|
221
|
+
* key that's stable across retries of the same logical send (e.g. the
|
|
222
|
+
* Reports row id), so a network blip during stamping doesn't cause a
|
|
223
|
+
* duplicate email to the client.
|
|
224
|
+
*/
|
|
225
|
+
idempotencyKey?: string;
|
|
226
|
+
};
|
|
227
|
+
type ResendSendResult = {
|
|
228
|
+
messageId: string;
|
|
229
|
+
};
|
|
230
|
+
type ResendClient = {
|
|
231
|
+
send: (input: ResendSendInput) => Promise<ResendSendResult>;
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
type OrchestrateOptions = {
|
|
235
|
+
resend?: ResendClient;
|
|
236
|
+
};
|
|
237
|
+
declare function sendApprovedReports(options?: OrchestrateOptions): Promise<{
|
|
238
|
+
output: string;
|
|
239
|
+
code: number;
|
|
240
|
+
}>;
|
|
241
|
+
|
|
242
|
+
type RenderResult = {
|
|
243
|
+
html: string;
|
|
244
|
+
warnings: Array<{
|
|
245
|
+
line: number;
|
|
246
|
+
message: string;
|
|
247
|
+
}>;
|
|
248
|
+
};
|
|
249
|
+
declare function renderReportHtml(data: ReportData): Promise<RenderResult>;
|
|
250
|
+
|
|
251
|
+
type DueItem = {
|
|
252
|
+
site: WebsiteRow;
|
|
253
|
+
reportType: ReportType;
|
|
254
|
+
/** Inclusive: the day the next report became due. */
|
|
255
|
+
dueDate: Date;
|
|
256
|
+
/** ISO date of the last `Sent at` for this (site, type), or null if there's never been one. */
|
|
257
|
+
lastSent: string | null;
|
|
258
|
+
};
|
|
259
|
+
/**
|
|
260
|
+
* Computes which (site, type) pairs are due as of `today`.
|
|
261
|
+
*
|
|
262
|
+
* Algorithm per (site, type):
|
|
263
|
+
* 1. If freq === "None", skip.
|
|
264
|
+
* 2. baseDate = max(last Sent at for this type, site's `maintenance/testing day` fallback).
|
|
265
|
+
* 3. If no baseDate exists at all, the site is due now.
|
|
266
|
+
* 4. dueDate = baseDate + frequency months.
|
|
267
|
+
* 5. Due iff startOfDay(today) >= startOfDay(dueDate).
|
|
268
|
+
*/
|
|
269
|
+
declare function findDueReports(websites: WebsiteRow[], reports: ReportRow[], today: Date): DueItem[];
|
|
270
|
+
|
|
271
|
+
export { ALL_AUDIT_NAMES, ALL_RECIPE_NAMES, AuditName, AuditResult, type BumpDepsOptions, type ConvertToPnpmOptions, type DraftOptions, type DraftResult, type DueItem, type HeaderImage, InventoryProvider, type LighthouseScores, type LocalPathOptions, type OnboardAudit, type OnboardOptions, type OrchestrateOptions, RecipeName, RecipeResult, type RenderResult, type ReportData, type ReportType, Site, type UpgradeSvelte4to5Options, a11yAudit, bumpDeps, convertToPnpm, depsAudit, draftReportForSite, findDueReports, fromJsonFile, isRecipeName, lighthouseAudit, lintAudit, localPath, onboard, renderReportHtml, runAudits, runAuditsAcross, securityAudit, sendApprovedReports, svelteCodemods, upgradeSvelte4to5 };
|