@beesolve/analytics-processor 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCS.md +23 -3
- package/dist/cdk.js +46 -0
- package/dist/dailyRollup/dailyRollup.mjs.map +2 -2
- package/dist/hourly/hourly.mjs +3 -3
- package/dist/hourly/hourly.mjs.map +3 -3
- package/dist/index.d.ts +273 -11
- package/dist/index.js +579 -67
- package/dist/monthlyRollup/monthlyRollup.mjs.map +2 -2
- package/dist/sitemap/bowser-UJEXXM6S.mjs +2 -0
- package/dist/sitemap/bowser-UJEXXM6S.mjs.map +7 -0
- package/dist/sitemap/chunk-3UGRDNDZ.mjs +6 -0
- package/dist/sitemap/chunk-3UGRDNDZ.mjs.map +7 -0
- package/dist/sitemap/chunk-BH7ZEBAB.mjs +2 -0
- package/dist/sitemap/chunk-BH7ZEBAB.mjs.map +7 -0
- package/dist/sitemap/chunk-CFZ5JWD3.mjs +2 -0
- package/dist/sitemap/chunk-CFZ5JWD3.mjs.map +7 -0
- package/dist/sitemap/chunk-KRS5YV2Z.mjs +2 -0
- package/dist/sitemap/chunk-KRS5YV2Z.mjs.map +7 -0
- package/dist/sitemap/chunk-LB33VBGK.mjs +2 -0
- package/dist/sitemap/chunk-LB33VBGK.mjs.map +7 -0
- package/dist/sitemap/chunk-OC3UN3OS.mjs +2 -0
- package/dist/sitemap/chunk-OC3UN3OS.mjs.map +7 -0
- package/dist/sitemap/chunk-PD2XGJQD.mjs +10 -0
- package/dist/sitemap/chunk-PD2XGJQD.mjs.map +7 -0
- package/dist/sitemap/chunk-QPD5NJHJ.mjs +2 -0
- package/dist/sitemap/chunk-QPD5NJHJ.mjs.map +7 -0
- package/dist/sitemap/chunk-REMPUQ6B.mjs +19 -0
- package/dist/sitemap/chunk-REMPUQ6B.mjs.map +7 -0
- package/dist/sitemap/chunk-SNCZ4GCT.mjs +2 -0
- package/dist/sitemap/chunk-SNCZ4GCT.mjs.map +7 -0
- package/dist/sitemap/chunk-TZ6TJSKE.mjs +10 -0
- package/dist/sitemap/chunk-TZ6TJSKE.mjs.map +7 -0
- package/dist/sitemap/chunk-YMGL4RSC.mjs +2 -0
- package/dist/sitemap/chunk-YMGL4RSC.mjs.map +7 -0
- package/dist/sitemap/chunk-YY2HYMK3.mjs +4 -0
- package/dist/sitemap/chunk-YY2HYMK3.mjs.map +7 -0
- package/dist/sitemap/client-WGCJRHWA.mjs +2 -0
- package/dist/sitemap/client-WGCJRHWA.mjs.map +7 -0
- package/dist/sitemap/dist-es-3FAKVHIH.mjs +2 -0
- package/dist/sitemap/dist-es-3FAKVHIH.mjs.map +7 -0
- package/dist/sitemap/dist-es-A36NQ5CO.mjs +2 -0
- package/dist/sitemap/dist-es-A36NQ5CO.mjs.map +7 -0
- package/dist/sitemap/dist-es-F7GXZJIC.mjs +3 -0
- package/dist/sitemap/dist-es-F7GXZJIC.mjs.map +7 -0
- package/dist/sitemap/dist-es-GRXF7RTK.mjs +2 -0
- package/dist/sitemap/dist-es-GRXF7RTK.mjs.map +7 -0
- package/dist/sitemap/dist-es-OKUHAI6O.mjs +2 -0
- package/dist/sitemap/dist-es-OKUHAI6O.mjs.map +7 -0
- package/dist/sitemap/dist-es-P7BXOYHO.mjs +2 -0
- package/dist/sitemap/dist-es-P7BXOYHO.mjs.map +7 -0
- package/dist/sitemap/dist-es-SQ53M5JX.mjs +7 -0
- package/dist/sitemap/dist-es-SQ53M5JX.mjs.map +7 -0
- package/dist/sitemap/dist-es-TCGA3UGX.mjs +2 -0
- package/dist/sitemap/dist-es-TCGA3UGX.mjs.map +7 -0
- package/dist/sitemap/dist-es-UXKF5GQY.mjs +3 -0
- package/dist/sitemap/dist-es-UXKF5GQY.mjs.map +7 -0
- package/dist/sitemap/dist-es-YJ4PQZC7.mjs +2 -0
- package/dist/sitemap/dist-es-YJ4PQZC7.mjs.map +7 -0
- package/dist/sitemap/event-streams-6V3Q6GHC.mjs +2 -0
- package/dist/sitemap/event-streams-6V3Q6GHC.mjs.map +7 -0
- package/dist/sitemap/loadCognitoIdentity-RIENBHOX.mjs +2 -0
- package/dist/sitemap/loadCognitoIdentity-RIENBHOX.mjs.map +7 -0
- package/dist/sitemap/loadSso-DTQ4R4CV.mjs +2 -0
- package/dist/sitemap/loadSso-DTQ4R4CV.mjs.map +7 -0
- package/dist/sitemap/loadSts-GZDTRQPT.mjs +2 -0
- package/dist/sitemap/loadSts-GZDTRQPT.mjs.map +7 -0
- package/dist/sitemap/signin-6D536OAO.mjs +2 -0
- package/dist/sitemap/signin-6D536OAO.mjs.map +7 -0
- package/dist/sitemap/sitemap.mjs +3 -0
- package/dist/sitemap/sitemap.mjs.map +7 -0
- package/dist/sitemap/sso-oidc-T5CK3NX3.mjs +2 -0
- package/dist/sitemap/sso-oidc-T5CK3NX3.mjs.map +7 -0
- package/dist/sitemap/sts-62ECLMPL.mjs +2 -0
- package/dist/sitemap/sts-62ECLMPL.mjs.map +7 -0
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ declare const dimensions: readonly ["status", "country", "device", "path"];
|
|
|
7
7
|
type Dimension = (typeof dimensions)[number];
|
|
8
8
|
declare const appliedSources: readonly ["v1", "v2"];
|
|
9
9
|
type AppliedSource = (typeof appliedSources)[number];
|
|
10
|
+
type MarkerGrain = Grain | "sitemap";
|
|
10
11
|
type TransactWriteItem = NonNullable<TransactWriteCommandInput["TransactItems"]>[number];
|
|
11
12
|
type PutMembers = NonNullable<TransactWriteItem["Put"]>;
|
|
12
13
|
interface TransactPutItem {
|
|
@@ -28,11 +29,11 @@ declare class AppliedMarkers {
|
|
|
28
29
|
readonly reverseIndexName?: string;
|
|
29
30
|
});
|
|
30
31
|
readonly isApplied: (props: {
|
|
31
|
-
readonly grain:
|
|
32
|
+
readonly grain: MarkerGrain;
|
|
32
33
|
readonly periodKey: string;
|
|
33
34
|
}) => Promise<boolean>;
|
|
34
35
|
readonly buildMarkerPut: (props: {
|
|
35
|
-
readonly grain:
|
|
36
|
+
readonly grain: MarkerGrain;
|
|
36
37
|
readonly periodKey: string;
|
|
37
38
|
readonly source: AppliedSource;
|
|
38
39
|
readonly ttl?: number;
|
|
@@ -142,6 +143,18 @@ interface HourlyAthenaResult {
|
|
|
142
143
|
hits: number;
|
|
143
144
|
}>;
|
|
144
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Start an Athena statement, poll until it succeeds, and return every result
|
|
148
|
+
* row as raw string cells (header row dropped). Shared by the hourly query and
|
|
149
|
+
* the sitemap monthly query so both use one polling/paging implementation.
|
|
150
|
+
*/
|
|
151
|
+
declare function startAndFetchRows({ athena, database, workgroup, outputLocation, queryString }: {
|
|
152
|
+
athena: Pick<AthenaClient, "send">;
|
|
153
|
+
database: string;
|
|
154
|
+
workgroup: string;
|
|
155
|
+
outputLocation?: string;
|
|
156
|
+
queryString: string;
|
|
157
|
+
}): Promise<Array<Array<string | undefined>>>;
|
|
145
158
|
declare function runHourlyAthenaQuery({ athena, database, table, workgroup, outputLocation, source, hourKey, topPaths }: {
|
|
146
159
|
athena: Pick<AthenaClient, "send">;
|
|
147
160
|
database: string;
|
|
@@ -212,8 +225,13 @@ declare const configSchema: v3.ObjectSchema<{
|
|
|
212
225
|
readonly sk: v3.LiteralSchema<"analytics", undefined>;
|
|
213
226
|
readonly startKey: v3.StringSchema<undefined>;
|
|
214
227
|
readonly startedAt: v3.StringSchema<undefined>;
|
|
228
|
+
readonly sitemapUrl: v3.OptionalSchema<v3.StringSchema<undefined>, undefined>;
|
|
215
229
|
}, undefined>;
|
|
216
230
|
type AnalyticsConfig = v3.InferOutput<typeof configSchema>;
|
|
231
|
+
declare const sitemapConfigSchema: v3.LooseObjectSchema<{
|
|
232
|
+
readonly sitemapUrl: v3.OptionalSchema<v3.StringSchema<undefined>, undefined>;
|
|
233
|
+
}, undefined>;
|
|
234
|
+
type SitemapConfig = v3.InferOutput<typeof sitemapConfigSchema>;
|
|
217
235
|
declare class Config {
|
|
218
236
|
private readonly props;
|
|
219
237
|
constructor(props: {
|
|
@@ -221,6 +239,10 @@ declare class Config {
|
|
|
221
239
|
readonly tableName: string;
|
|
222
240
|
});
|
|
223
241
|
readonly get: () => Promise<AnalyticsConfig | null>;
|
|
242
|
+
readonly getSitemapConfig: () => Promise<SitemapConfig>;
|
|
243
|
+
readonly setSitemapUrl: ({ sitemapUrl }: {
|
|
244
|
+
readonly sitemapUrl: string;
|
|
245
|
+
}) => Promise<void>;
|
|
224
246
|
/**
|
|
225
247
|
* Records the earliest ingested hour the first time any data lands, so the UI
|
|
226
248
|
* can clamp navigation to [startKey, now]. Idempotent: once `startKey` exists
|
|
@@ -362,7 +384,25 @@ interface RollupModels {
|
|
|
362
384
|
readonly breakdowns: Pick<Breakdowns, "buildUpdates" | "getForPeriod">;
|
|
363
385
|
readonly markers: Pick<AppliedMarkers, "isApplied" | "buildMarkerPut">;
|
|
364
386
|
}
|
|
387
|
+
declare function sendTransacted({ dynamo, leading, rest }: {
|
|
388
|
+
dynamo: Pick<DynamoDBDocumentClient5, "send">;
|
|
389
|
+
leading: Array<TransactItem>;
|
|
390
|
+
rest: Array<TransactItem>;
|
|
391
|
+
}): Promise<ProcessHourResult>;
|
|
392
|
+
declare function isMarkerRaceError(error: unknown): boolean;
|
|
365
393
|
type View = Grain | "year";
|
|
394
|
+
/**
|
|
395
|
+
* How a bucket's value was obtained, so the UI can tell "no traffic" apart from
|
|
396
|
+
* "not calculated yet":
|
|
397
|
+
* - `sealed`: a finalized, rolled-up period read from its stored aggregate. A
|
|
398
|
+
* zero-hit sealed bucket is genuine "no traffic".
|
|
399
|
+
* - `partial`: an in-progress period computed live from the finer grain; the
|
|
400
|
+
* value is real but may still grow.
|
|
401
|
+
* - `pending`: a period past its expected processing time with no stored data
|
|
402
|
+
* and nothing computable yet — awaiting processing.
|
|
403
|
+
*/
|
|
404
|
+
declare const bucketStates: readonly ["sealed", "partial", "pending"];
|
|
405
|
+
type BucketState = (typeof bucketStates)[number];
|
|
366
406
|
interface ResolveModels {
|
|
367
407
|
readonly totals: Pick<Totals, "queryWindow" | "getOne">;
|
|
368
408
|
readonly breakdowns: Pick<Breakdowns, "getForPeriod">;
|
|
@@ -370,15 +410,21 @@ interface ResolveModels {
|
|
|
370
410
|
}
|
|
371
411
|
/**
|
|
372
412
|
* Resolves one bucket's totals, computing an in-progress period on the fly from
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
413
|
+
* exactly one grain finer, following only the current edge deeper.
|
|
414
|
+
*
|
|
415
|
+
* A sealed period (strictly past, rollup marker applied) is read from its stored
|
|
416
|
+
* aggregate. Otherwise the period is the sum of its children at the next finer
|
|
417
|
+
* grain, where every already-complete child is taken from its stored aggregate
|
|
418
|
+
* and only the single in-progress child is resolved recursively:
|
|
419
|
+
*
|
|
420
|
+
* - partial day = stored/queried hours `00..currentHour`
|
|
421
|
+
* - partial month = stored days `01..currentDay-1` + the partial current day
|
|
422
|
+
* - partial year = stored months `01..currentMonth-1` + the partial current month
|
|
377
423
|
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
424
|
+
* So a partial month never fans out to hours for its finished days (it trusts
|
|
425
|
+
* their day aggregate) — only the one current day drills into hours. Each level
|
|
426
|
+
* is one ranged query, keeping the read count bounded (a year touches ~12
|
|
427
|
+
* months + ~31 days + ~24 hours) and the request sub-second.
|
|
382
428
|
*/
|
|
383
429
|
declare function resolveTotalsLive({ models, grain, periodKey, now }: {
|
|
384
430
|
readonly models: ResolveModels;
|
|
@@ -393,6 +439,222 @@ declare function resolveBreakdownLive({ models, dimension, grain, periodKey, now
|
|
|
393
439
|
readonly periodKey: string;
|
|
394
440
|
readonly now: Date;
|
|
395
441
|
}): Promise<Array<BreakdownRow>>;
|
|
442
|
+
/**
|
|
443
|
+
* Classifies a bucket as sealed / partial / pending without recomputing its
|
|
444
|
+
* value. A sealed bucket is a finalized rollup (its marker is applied), so a
|
|
445
|
+
* zero-hit sealed bucket is genuine "no traffic". A non-sealed bucket that
|
|
446
|
+
* yielded data is in-progress (`partial`); one with nothing to show is awaiting
|
|
447
|
+
* processing (`pending`).
|
|
448
|
+
*/
|
|
449
|
+
declare function classifyBucketState({ models, grain, periodKey, now, hasData }: {
|
|
450
|
+
readonly models: ResolveModels;
|
|
451
|
+
readonly grain: Grain;
|
|
452
|
+
readonly periodKey: string;
|
|
453
|
+
readonly now: Date;
|
|
454
|
+
readonly hasData: boolean;
|
|
455
|
+
}): Promise<BucketState>;
|
|
456
|
+
import { AthenaClient as AthenaClient3 } from "@aws-sdk/client-athena";
|
|
457
|
+
import { DynamoDBDocumentClient as DynamoDBDocumentClient6, TransactWriteCommandInput as TransactWriteCommandInput5 } from "@aws-sdk/lib-dynamodb";
|
|
458
|
+
import * as v5 from "valibot";
|
|
459
|
+
type TransactWriteItem4 = NonNullable<TransactWriteCommandInput5["TransactItems"]>[number];
|
|
460
|
+
type UpdateMembers3 = NonNullable<TransactWriteItem4["Update"]>;
|
|
461
|
+
/**
|
|
462
|
+
* Collapse a single trailing slash on a path so `/blog/` and `/blog` fold
|
|
463
|
+
* together. Root `/` is preserved. Already-unslashed paths are returned as-is.
|
|
464
|
+
*/
|
|
465
|
+
declare function canonicalPath(path: string): string;
|
|
466
|
+
/**
|
|
467
|
+
* Parse an absolute sitemap `<loc>` URL and reduce it to a canonical path:
|
|
468
|
+
* origin, query and fragment are stripped and a trailing slash is collapsed.
|
|
469
|
+
* Throws on input the `URL` class cannot parse.
|
|
470
|
+
*/
|
|
471
|
+
declare function normalizeSitemapLoc(loc: string): string;
|
|
472
|
+
/**
|
|
473
|
+
* Extract every `<loc>` from a flat `<urlset>` sitemap, XML-unescape and
|
|
474
|
+
* normalize each to a path, and dedupe preserving first-seen order (so a
|
|
475
|
+
* `/blog` and `/blog/` pair collapse to one entry). Throws on a
|
|
476
|
+
* `<sitemapindex>` document, which is not supported.
|
|
477
|
+
*/
|
|
478
|
+
declare function parseSitemap(xml: string): Array<string>;
|
|
479
|
+
/**
|
|
480
|
+
* Identifies this crawler's outbound sitemap requests so site operators can
|
|
481
|
+
* distinguish them in their access logs.
|
|
482
|
+
*/
|
|
483
|
+
declare const sitemapUserAgent = "@beesolve/analytics-processor sitemap fetcher (+https://github.com/BeeSolve/packages)";
|
|
484
|
+
/**
|
|
485
|
+
* Fetch a sitemap over HTTP and return its normalized, deduped paths. Throws
|
|
486
|
+
* with the response status if the request is not successful.
|
|
487
|
+
*/
|
|
488
|
+
declare function fetchSitemapPaths(url: string): Promise<Array<string>>;
|
|
489
|
+
interface SitemapHourCounts {
|
|
490
|
+
readonly path: string;
|
|
491
|
+
readonly hits: number;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Build an Athena statement that counts hits per `path` for a single UTC hour,
|
|
495
|
+
* restricted to the given sitemap paths. The log-side URI is slash-collapsed in
|
|
496
|
+
* SQL via {@link canonicalUriExpr} in both the `WHERE ... IN` and the
|
|
497
|
+
* `GROUP BY`, mirroring {@link canonicalPath}, so `/blog` and the 301 hit on
|
|
498
|
+
* `/blog/` both count against `/blog`. An empty `paths` yields a valid zero-row
|
|
499
|
+
* statement (`WHERE 1 = 0`).
|
|
500
|
+
*/
|
|
501
|
+
declare function buildSitemapHourlyQuery({ table, source, hourKey, paths }: {
|
|
502
|
+
table: string;
|
|
503
|
+
source: AppliedSource;
|
|
504
|
+
hourKey: string;
|
|
505
|
+
paths: Array<string>;
|
|
506
|
+
}): string;
|
|
507
|
+
/**
|
|
508
|
+
* Run {@link buildSitemapHourlyQuery} and return one {@link SitemapHourCounts}
|
|
509
|
+
* per path with hits for that hour. Short-circuits to `[]` without calling
|
|
510
|
+
* Athena when `paths` is empty.
|
|
511
|
+
*/
|
|
512
|
+
declare function runSitemapHourlyQuery({ athena, database, table, workgroup, outputLocation, source, hourKey, paths }: {
|
|
513
|
+
athena: Pick<AthenaClient3, "send">;
|
|
514
|
+
database: string;
|
|
515
|
+
table: string;
|
|
516
|
+
workgroup: string;
|
|
517
|
+
outputLocation?: string;
|
|
518
|
+
source: AppliedSource;
|
|
519
|
+
hourKey: string;
|
|
520
|
+
paths: Array<string>;
|
|
521
|
+
}): Promise<Array<SitemapHourCounts>>;
|
|
522
|
+
interface SitemapMonthCounts {
|
|
523
|
+
readonly path: string;
|
|
524
|
+
readonly month: string;
|
|
525
|
+
readonly days: Record<string, number>;
|
|
526
|
+
readonly hits: number;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Build an Athena statement that counts hits per `(day-of-month, path)` across
|
|
530
|
+
* a whole `YYYY-MM`, restricted to the given sitemap paths. One scan of the
|
|
531
|
+
* month's partitions replaces 720 single-hour scans, which is why backfill uses
|
|
532
|
+
* this instead of {@link buildSitemapHourlyQuery}. The log-side URI is
|
|
533
|
+
* slash-collapsed in SQL via {@link canonicalUriExpr} in both the `WHERE ... IN`
|
|
534
|
+
* and the `GROUP BY`. An empty `paths` yields a valid zero-row statement.
|
|
535
|
+
*/
|
|
536
|
+
declare function buildSitemapMonthlyQuery({ table, source, monthKey, paths }: {
|
|
537
|
+
table: string;
|
|
538
|
+
source: AppliedSource;
|
|
539
|
+
monthKey: string;
|
|
540
|
+
paths: Array<string>;
|
|
541
|
+
}): string;
|
|
542
|
+
/**
|
|
543
|
+
* Run {@link buildSitemapMonthlyQuery} and reshape the rows into one
|
|
544
|
+
* {@link SitemapMonthCounts} per path, with day-of-month zero-padded to `dd`.
|
|
545
|
+
* Short-circuits to `[]` without calling Athena when `paths` is empty.
|
|
546
|
+
*/
|
|
547
|
+
declare function runSitemapMonthlyQuery({ athena, database, table, workgroup, outputLocation, source, monthKey, paths }: {
|
|
548
|
+
athena: Pick<AthenaClient3, "send">;
|
|
549
|
+
database: string;
|
|
550
|
+
table: string;
|
|
551
|
+
workgroup: string;
|
|
552
|
+
outputLocation?: string;
|
|
553
|
+
source: AppliedSource;
|
|
554
|
+
monthKey: string;
|
|
555
|
+
paths: Array<string>;
|
|
556
|
+
}): Promise<Array<SitemapMonthCounts>>;
|
|
557
|
+
interface ProcessSitemapModels {
|
|
558
|
+
readonly sitemapUrlStats: Pick<SitemapUrlStats, "buildAdd">;
|
|
559
|
+
readonly markers: Pick<AppliedMarkers, "isApplied" | "buildMarkerPut">;
|
|
560
|
+
}
|
|
561
|
+
interface ProcessSitemapAthena {
|
|
562
|
+
readonly client: Pick<AthenaClient3, "send">;
|
|
563
|
+
readonly database: string;
|
|
564
|
+
readonly table: string;
|
|
565
|
+
readonly workgroup: string;
|
|
566
|
+
readonly outputLocation?: string;
|
|
567
|
+
}
|
|
568
|
+
interface ProcessSitemapOptions {
|
|
569
|
+
readonly markerTtlDays?: number;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Incrementally add a single UTC hour's per-path hits to each sitemap URL's
|
|
573
|
+
* `(path, month)` item, guarded by an applied-marker so the hour is counted at
|
|
574
|
+
* most once. Returns `{ status: "skipped" }` when the hour is already applied,
|
|
575
|
+
* and `{ status: "applied", urls }` otherwise (`urls: 0` when nothing matched).
|
|
576
|
+
*/
|
|
577
|
+
declare function processSitemapHour({ hourKey, source, paths, models, athena, options, dynamo }: {
|
|
578
|
+
hourKey: string;
|
|
579
|
+
source: AppliedSource;
|
|
580
|
+
paths: Array<string>;
|
|
581
|
+
models: ProcessSitemapModels;
|
|
582
|
+
athena: ProcessSitemapAthena;
|
|
583
|
+
options?: ProcessSitemapOptions;
|
|
584
|
+
dynamo: Pick<DynamoDBDocumentClient6, "send">;
|
|
585
|
+
}): Promise<{
|
|
586
|
+
status: "applied" | "skipped";
|
|
587
|
+
urls: number;
|
|
588
|
+
}>;
|
|
589
|
+
interface ProcessSitemapMonthModels {
|
|
590
|
+
readonly sitemapUrlStats: Pick<SitemapUrlStats, "overwriteMany">;
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Recompute a whole month's per-day hits in a single Athena scan and overwrite
|
|
594
|
+
* each `(path, month)` item with `SET`. This is the backfill path: one scan of
|
|
595
|
+
* the month replaces 720 single-hour scans, and `SET` is idempotent so reruns
|
|
596
|
+
* are safe and no applied-marker is needed. The live hourly cron uses
|
|
597
|
+
* {@link processSitemapHour} (incremental `ADD`) instead, because going forward
|
|
598
|
+
* it only ever has one new hour of data. Returns `{ urls: 0 }` without calling
|
|
599
|
+
* Athena when `paths` is empty.
|
|
600
|
+
*/
|
|
601
|
+
declare function processSitemapMonth({ monthKey, source, paths, models, athena }: {
|
|
602
|
+
monthKey: string;
|
|
603
|
+
source: AppliedSource;
|
|
604
|
+
paths: Array<string>;
|
|
605
|
+
models: ProcessSitemapMonthModels;
|
|
606
|
+
athena: ProcessSitemapAthena;
|
|
607
|
+
}): Promise<{
|
|
608
|
+
urls: number;
|
|
609
|
+
}>;
|
|
610
|
+
declare const sitemapUrlStatSchema: v5.LooseObjectSchema<{
|
|
611
|
+
readonly pk: v5.StringSchema<undefined>;
|
|
612
|
+
readonly sk: v5.StringSchema<undefined>;
|
|
613
|
+
readonly path: v5.StringSchema<undefined>;
|
|
614
|
+
readonly month: v5.StringSchema<undefined>;
|
|
615
|
+
readonly hits: v5.NumberSchema<undefined>;
|
|
616
|
+
readonly updatedAt: v5.NumberSchema<undefined>;
|
|
617
|
+
}, undefined>;
|
|
618
|
+
type SitemapUrlStat = v5.InferOutput<typeof sitemapUrlStatSchema>;
|
|
619
|
+
interface SitemapUrlStatRecord {
|
|
620
|
+
readonly pk: string;
|
|
621
|
+
readonly sk: string;
|
|
622
|
+
readonly path: string;
|
|
623
|
+
readonly month: string;
|
|
624
|
+
readonly hits: number;
|
|
625
|
+
readonly updatedAt: number;
|
|
626
|
+
readonly days: Record<string, number>;
|
|
627
|
+
}
|
|
628
|
+
declare class SitemapUrlStats {
|
|
629
|
+
private readonly props;
|
|
630
|
+
constructor(props: {
|
|
631
|
+
readonly dynamo: Pick<DynamoDBDocumentClient6, "send">;
|
|
632
|
+
readonly tableName: string;
|
|
633
|
+
readonly reverseIndexName?: string;
|
|
634
|
+
});
|
|
635
|
+
readonly buildAdd: ({ path, month, dayAttr, hits }: {
|
|
636
|
+
readonly path: string;
|
|
637
|
+
readonly month: string;
|
|
638
|
+
readonly dayAttr: string;
|
|
639
|
+
readonly hits: number;
|
|
640
|
+
}) => TransactItem;
|
|
641
|
+
readonly overwriteMany: (stats: Array<SitemapMonthCounts>) => Promise<void>;
|
|
642
|
+
readonly buildOverwrite: ({ path, month, days, hits }: {
|
|
643
|
+
readonly path: string;
|
|
644
|
+
readonly month: string;
|
|
645
|
+
readonly days: Record<string, number>;
|
|
646
|
+
readonly hits: number;
|
|
647
|
+
}) => UpdateMembers3;
|
|
648
|
+
readonly getForUrl: ({ path, startMonth, endMonth }: {
|
|
649
|
+
readonly path: string;
|
|
650
|
+
readonly startMonth: string;
|
|
651
|
+
readonly endMonth: string;
|
|
652
|
+
}) => Promise<Array<SitemapUrlStatRecord>>;
|
|
653
|
+
readonly getForMonth: ({ month }: {
|
|
654
|
+
readonly month: string;
|
|
655
|
+
}) => Promise<Array<SitemapUrlStatRecord>>;
|
|
656
|
+
private readonly parseOne;
|
|
657
|
+
}
|
|
396
658
|
declare function yearKey(date: Date): string;
|
|
397
659
|
declare function monthKey2(date: Date): string;
|
|
398
660
|
declare function dayKey2(date: Date): string;
|
|
@@ -423,4 +685,4 @@ declare function hoursBetween({ from, to }: {
|
|
|
423
685
|
from: Date;
|
|
424
686
|
to: Date;
|
|
425
687
|
}): Array<string>;
|
|
426
|
-
export { AnalyticsConfig, AppliedMarker, AppliedMarkers, AppliedSource, AthenaColumnMap, BreakdownInput, BreakdownItem, BreakdownRow, Breakdowns, Config, DeviceBucket, Dimension, Grain, HourlyAthenaResult, HourlyAthenaTotals, ProcessHourAthena, ProcessHourModels, ProcessHourOptions, ProcessHourResult, ResolveModels, SummedTotals, Totals, TotalsInput, TotalsItem, TransactItem, View, appliedMarkerSchema, appliedSources, applyDailyRollup, applyMonthlyRollup, breakdownSchema, buildHourlyQuery, chunkTransactItems, classifyDevice, columnMaps, configSchema, dayKey2 as dayKey, dimensions, grainForPeriodKey, grains, hourKey2 as hourKey, hourKeyParts, hoursBetween, maxWindowFor, monthKey2 as monthKey, parsePeriodKey, processHour, requiredRecordFields, resolveBreakdownLive, resolveTotalsLive, runHourlyAthenaQuery, shiftAnchor, sumBreakdown, sumTotals, topNWithOther, totalsSchema, windowKeys, yearKey };
|
|
688
|
+
export { AnalyticsConfig, AppliedMarker, AppliedMarkers, AppliedSource, AthenaColumnMap, BreakdownInput, BreakdownItem, BreakdownRow, Breakdowns, BucketState, Config, DeviceBucket, Dimension, Grain, HourlyAthenaResult, HourlyAthenaTotals, MarkerGrain, ProcessHourAthena, ProcessHourModels, ProcessHourOptions, ProcessHourResult, ProcessSitemapAthena, ProcessSitemapModels, ProcessSitemapMonthModels, ProcessSitemapOptions, ResolveModels, SitemapConfig, SitemapHourCounts, SitemapMonthCounts, SitemapUrlStat, SitemapUrlStatRecord, SitemapUrlStats, SummedTotals, Totals, TotalsInput, TotalsItem, TransactItem, View, appliedMarkerSchema, appliedSources, applyDailyRollup, applyMonthlyRollup, breakdownSchema, bucketStates, buildHourlyQuery, buildSitemapHourlyQuery, buildSitemapMonthlyQuery, canonicalPath, chunkTransactItems, classifyBucketState, classifyDevice, columnMaps, configSchema, dayKey2 as dayKey, dimensions, fetchSitemapPaths, grainForPeriodKey, grains, hourKey2 as hourKey, hourKeyParts, hoursBetween, isMarkerRaceError, maxWindowFor, monthKey2 as monthKey, normalizeSitemapLoc, parsePeriodKey, parseSitemap, processHour, processSitemapHour, processSitemapMonth, requiredRecordFields, resolveBreakdownLive, resolveTotalsLive, runHourlyAthenaQuery, runSitemapHourlyQuery, runSitemapMonthlyQuery, sendTransacted, shiftAnchor, sitemapUrlStatSchema, sitemapUserAgent, startAndFetchRows, sumBreakdown, sumTotals, topNWithOther, totalsSchema, windowKeys, yearKey };
|