@usine/github 0.1.0 → 0.1.2

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.
Files changed (72) hide show
  1. package/README.md +14 -4
  2. package/dist/access.d.ts +48 -0
  3. package/dist/access.d.ts.map +1 -0
  4. package/dist/access.js +53 -0
  5. package/dist/access.js.map +1 -0
  6. package/dist/credentials.d.ts +28 -0
  7. package/dist/credentials.d.ts.map +1 -0
  8. package/dist/credentials.js +22 -0
  9. package/dist/credentials.js.map +1 -0
  10. package/dist/error.d.ts +36 -0
  11. package/dist/error.d.ts.map +1 -0
  12. package/dist/error.js +48 -0
  13. package/dist/error.js.map +1 -0
  14. package/dist/github-app.d.ts +17 -10
  15. package/dist/github-app.d.ts.map +1 -1
  16. package/dist/github-app.js +31 -16
  17. package/dist/github-app.js.map +1 -1
  18. package/dist/http.d.ts +3 -4
  19. package/dist/http.d.ts.map +1 -1
  20. package/dist/http.js +4 -4
  21. package/dist/http.js.map +1 -1
  22. package/dist/installation.d.ts +48 -0
  23. package/dist/installation.d.ts.map +1 -0
  24. package/dist/installation.js +40 -0
  25. package/dist/installation.js.map +1 -0
  26. package/dist/item-writer.d.ts +7 -6
  27. package/dist/item-writer.d.ts.map +1 -1
  28. package/dist/item-writer.js +5 -4
  29. package/dist/item-writer.js.map +1 -1
  30. package/dist/jwt.d.ts +6 -5
  31. package/dist/jwt.d.ts.map +1 -1
  32. package/dist/jwt.js +4 -4
  33. package/dist/jwt.js.map +1 -1
  34. package/dist/label-writer.d.ts +23 -0
  35. package/dist/label-writer.d.ts.map +1 -0
  36. package/dist/label-writer.js +54 -0
  37. package/dist/label-writer.js.map +1 -0
  38. package/dist/local-secrets.d.ts +5 -5
  39. package/dist/local-secrets.d.ts.map +1 -1
  40. package/dist/local-secrets.js +5 -5
  41. package/dist/local-secrets.js.map +1 -1
  42. package/dist/polling/content.d.ts +3 -0
  43. package/dist/polling/content.d.ts.map +1 -0
  44. package/dist/polling/content.js +24 -0
  45. package/dist/polling/content.js.map +1 -0
  46. package/dist/polling/detection.d.ts +55 -0
  47. package/dist/polling/detection.d.ts.map +1 -0
  48. package/dist/polling/detection.js +49 -0
  49. package/dist/polling/detection.js.map +1 -0
  50. package/dist/polling/labels.d.ts +31 -0
  51. package/dist/polling/labels.d.ts.map +1 -0
  52. package/dist/polling/labels.js +29 -0
  53. package/dist/polling/labels.js.map +1 -0
  54. package/dist/polling/{model.d.ts → payload.d.ts} +7 -66
  55. package/dist/polling/payload.d.ts.map +1 -0
  56. package/dist/polling/{model.js → payload.js} +12 -72
  57. package/dist/polling/payload.js.map +1 -0
  58. package/dist/polling/polling.d.ts +15 -9
  59. package/dist/polling/polling.d.ts.map +1 -1
  60. package/dist/polling/polling.js +49 -44
  61. package/dist/polling/polling.js.map +1 -1
  62. package/package.json +17 -5
  63. package/dist/index.d.ts +0 -7
  64. package/dist/index.d.ts.map +0 -1
  65. package/dist/index.js +0 -7
  66. package/dist/index.js.map +0 -1
  67. package/dist/model.d.ts +0 -128
  68. package/dist/model.d.ts.map +0 -1
  69. package/dist/model.js +0 -133
  70. package/dist/model.js.map +0 -1
  71. package/dist/polling/model.d.ts.map +0 -1
  72. package/dist/polling/model.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detection.js","sourceRoot":"","sources":["../../src/polling/detection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhD,4FAA4F;AAC5F,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAGrF,sGAAsG;AACtG,MAAM,OAAO,UAAW,SAAQ,MAAM,CAAC,KAAK,CAAa,0BAA0B,CAAC,CAAC;IACnF,SAAS,EAAE,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC;IAC7C,SAAS,EAAE,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,qBAAqB,CAAC;CACjE,CAAC;IACA,MAAM,CAAU,KAAK,GAAG,IAAI,UAAU,CAAC;QACrC,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE;QACxB,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE;KACzB,CAAC,CAAC;CACJ;AAED,+EAA+E;AAC/E,MAAM,OAAO,YAAa,SAAQ,MAAM,CAAC,WAAW,CAAe,4BAA4B,CAAC,CAC9F,cAAc,EACd;IACE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAC1D,SAAS,EAAE,MAAM,CAAC,WAAW;CAC9B,CACF;CAAG;AAEJ,qFAAqF;AACrF,MAAM,OAAO,kBAAmB,SAAQ,MAAM,CAAC,WAAW,CACxD,kCAAkC,CACnC,CAAC,oBAAoB,EAAE;IACtB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAC1D,SAAS,EAAE,MAAM,CAAC,WAAW;CAC9B,CAAC;CAAG;AAEL,yFAAyF;AACzF,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC,CAAC;AAG5E,qFAAqF;AACrF,MAAM,OAAO,qBAAsB,SAAQ,MAAM,CAAC,WAAW,CAC3D,qCAAqC,CACtC,CAAC,uBAAuB,EAAE;IACzB,MAAM,EAAE,UAAU;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC;IAC7C,+FAA+F;IAC/F,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAClD,MAAM,CAAC,sBAAsB,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAC7D;CACF,CAAC;CAAG;AAEL,yFAAyF;AACzF,MAAM,OAAO,iBAAkB,SAAQ,MAAM,CAAC,WAAW,CACvD,iCAAiC,CAClC,CAAC,mBAAmB,EAAE;IACrB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC;IAChC,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC,OAAO;IACvB,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC;IAC7C,+FAA+F;IAC/F,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAClD,MAAM,CAAC,sBAAsB,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAC7D;CACF,CAAC;CAAG;AAEL,wFAAwF;AACxF,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { Schema } from "effect";
2
+ /** A repository label name as returned by GitHub, preserved without case conversion. */
3
+ export declare const RepositoryLabelName: Schema.brand<Schema.NonEmptyString, "GitHubRepositoryLabelName">;
4
+ export type RepositoryLabelName = typeof RepositoryLabelName.Type;
5
+ /** GitHub stores label colors as six hex digits without the leading hash. */
6
+ export declare const RepositoryLabelColor: Schema.brand<Schema.String, "GitHubRepositoryLabelColor">;
7
+ export type RepositoryLabelColor = typeof RepositoryLabelColor.Type;
8
+ declare const RepositoryLabel_base: Schema.Class<RepositoryLabel, Schema.Struct<{
9
+ readonly name: Schema.brand<Schema.NonEmptyString, "GitHubRepositoryLabelName">;
10
+ readonly color: Schema.brand<Schema.String, "GitHubRepositoryLabelColor">;
11
+ readonly description: Schema.OptionFromNullOr<Schema.String>;
12
+ }>, {}>;
13
+ /** One repository label as GitHub defines it. The name routes lanes, and color and description are presentation only. */
14
+ export declare class RepositoryLabel extends RepositoryLabel_base {
15
+ }
16
+ declare const RepositoryLabelCatalog_base: Schema.Class<RepositoryLabelCatalog, Schema.Struct<{
17
+ readonly entityTag: Schema.OptionFromNullOr<Schema.brand<Schema.NonEmptyString, "GitHubEntityTag">>;
18
+ readonly labels: Schema.$Array<typeof RepositoryLabel>;
19
+ }>, {}>;
20
+ /** A complete label catalog with the ETag of its canonical REST URL. */
21
+ export declare class RepositoryLabelCatalog extends RepositoryLabelCatalog_base {
22
+ }
23
+ declare const RepositoryLabelsNotModified_base: Schema.Class<RepositoryLabelsNotModified, Schema.TaggedStruct<"RepositoryLabelsNotModified", {}>, {}>;
24
+ /** GitHub confirmed the catalog named by its ETag has not changed. */
25
+ export declare class RepositoryLabelsNotModified extends RepositoryLabelsNotModified_base {
26
+ }
27
+ /** A complete label catalog or confirmation that the cached catalog is unchanged. */
28
+ export declare const RepositoryLabelDetection: Schema.Union<readonly [typeof RepositoryLabelCatalog, typeof RepositoryLabelsNotModified]>;
29
+ export type RepositoryLabelDetection = typeof RepositoryLabelDetection.Type;
30
+ export {};
31
+ //# sourceMappingURL=labels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../src/polling/labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,wFAAwF;AACxF,eAAO,MAAM,mBAAmB,kEAE/B,CAAC;AACF,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAC,IAAI,CAAC;AAElE,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,2DAEiB,CAAC;AACnD,MAAM,MAAM,oBAAoB,GAAG,OAAO,oBAAoB,CAAC,IAAI,CAAC;;;;;;AAEpE,yHAAyH;AACzH,qBAAa,eAAgB,SAAQ,oBAMpC;CAAG;;;;;AAOJ,wEAAwE;AACxE,qBAAa,sBAAuB,SAAQ,2BAK1C;CAAG;;AAEL,sEAAsE;AACtE,qBAAa,2BAA4B,SAAQ,gCAEb;CAAG;AAEvC,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,4FAGnC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,OAAO,wBAAwB,CAAC,IAAI,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { Schema } from "effect";
2
+ import { EntityTag } from "./detection.js";
3
+ /** A repository label name as returned by GitHub, preserved without case conversion. */
4
+ export const RepositoryLabelName = Schema.NonEmptyString.pipe(Schema.brand("GitHubRepositoryLabelName"));
5
+ /** GitHub stores label colors as six hex digits without the leading hash. */
6
+ export const RepositoryLabelColor = Schema.String.check(Schema.isPattern(/^[0-9a-fA-F]{6}$/u, { message: "Expected a six-digit hex label color" })).pipe(Schema.brand("GitHubRepositoryLabelColor"));
7
+ /** One repository label as GitHub defines it. The name routes lanes, and color and description are presentation only. */
8
+ export class RepositoryLabel extends Schema.Class("@usine/github/RepositoryLabel")({
9
+ name: RepositoryLabelName,
10
+ color: RepositoryLabelColor,
11
+ description: Schema.OptionFromNullOr(Schema.String),
12
+ }) {
13
+ }
14
+ const uniqueLabelNames = Schema.makeFilter((labels) => new Set(labels.map(({ name }) => name)).size === labels.length, { message: "Expected unique label names" });
15
+ /** A complete label catalog with the ETag of its canonical REST URL. */
16
+ export class RepositoryLabelCatalog extends Schema.Class("@usine/github/RepositoryLabelCatalog")({
17
+ entityTag: Schema.OptionFromNullOr(EntityTag),
18
+ labels: Schema.Array(RepositoryLabel).check(uniqueLabelNames),
19
+ }) {
20
+ }
21
+ /** GitHub confirmed the catalog named by its ETag has not changed. */
22
+ export class RepositoryLabelsNotModified extends Schema.TaggedClass("@usine/github/RepositoryLabelsNotModified")("RepositoryLabelsNotModified", {}) {
23
+ }
24
+ /** A complete label catalog or confirmation that the cached catalog is unchanged. */
25
+ export const RepositoryLabelDetection = Schema.Union([
26
+ RepositoryLabelCatalog,
27
+ RepositoryLabelsNotModified,
28
+ ]);
29
+ //# sourceMappingURL=labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.js","sourceRoot":"","sources":["../../src/polling/labels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,wFAAwF;AACxF,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAC3D,MAAM,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAC1C,CAAC;AAGF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CACrD,MAAM,CAAC,SAAS,CAAC,mBAAmB,EAAE,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC,CAC3F,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAC;AAGnD,yHAAyH;AACzH,MAAM,OAAO,eAAgB,SAAQ,MAAM,CAAC,KAAK,CAAkB,+BAA+B,CAAC,CACjG;IACE,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,oBAAoB;IAC3B,WAAW,EAAE,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC;CACpD,CACF;CAAG;AAEJ,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,CACxC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,EAC1E,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAC3C,CAAC;AAEF,wEAAwE;AACxE,MAAM,OAAO,sBAAuB,SAAQ,MAAM,CAAC,KAAK,CACtD,sCAAsC,CACvC,CAAC;IACA,SAAS,EAAE,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;CAC9D,CAAC;CAAG;AAEL,sEAAsE;AACtE,MAAM,OAAO,2BAA4B,SAAQ,MAAM,CAAC,WAAW,CACjE,2CAA2C,CAC5C,CAAC,6BAA6B,EAAE,EAAE,CAAC;CAAG;AAEvC,qFAAqF;AACrF,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,KAAK,CAAC;IACnD,sBAAsB;IACtB,2BAA2B;CAC5B,CAAC,CAAC"}
@@ -1,68 +1,5 @@
1
1
  import { Schema } from "effect";
2
- /**
3
- * The payload keys that hold a `Timestamp` above. Bound to the slice schemas:
4
- * a field added to a slice with a `Timestamp` value MUST be listed here, or it
5
- * silently joins the content hash and re-fires every item once (ADR 0007 keeps
6
- * timestamps in the payload but out of the hash).
7
- */
8
- export declare const TIMESTAMP_FIELDS: ReadonlySet<string>;
9
- export declare const EntityTag: Schema.brand<Schema.NonEmptyString, "GitHubEntityTag">;
10
- export type EntityTag = typeof EntityTag.Type;
11
- export declare const RepositoryLabelName: Schema.brand<Schema.NonEmptyString, "GitHubRepositoryLabelName">;
12
- export type RepositoryLabelName = typeof RepositoryLabelName.Type;
13
- declare const RepositoryLabelCatalog_base: Schema.Class<RepositoryLabelCatalog, Schema.Struct<{
14
- readonly entityTag: Schema.OptionFromNullOr<Schema.brand<Schema.NonEmptyString, "GitHubEntityTag">>;
15
- readonly labels: Schema.$Array<Schema.brand<Schema.NonEmptyString, "GitHubRepositoryLabelName">>;
16
- }>, {}>;
17
- /** A complete label catalog and the ETag for its canonical REST URL. */
18
- export declare class RepositoryLabelCatalog extends RepositoryLabelCatalog_base {
19
- }
20
- declare const RepositoryLabelsNotModified_base: Schema.Class<RepositoryLabelsNotModified, Schema.TaggedStruct<"RepositoryLabelsNotModified", {}>, {}>;
21
- /** GitHub confirmed that the catalog named by its ETag has not changed. */
22
- export declare class RepositoryLabelsNotModified extends RepositoryLabelsNotModified_base {
23
- }
24
- export declare const RepositoryLabelDetection: Schema.Union<readonly [typeof RepositoryLabelCatalog, typeof RepositoryLabelsNotModified]>;
25
- export type RepositoryLabelDetection = typeof RepositoryLabelDetection.Type;
26
- declare const PollCursor_base: Schema.Class<PollCursor, Schema.Struct<{
27
- readonly entityTag: Schema.OptionFromNullOr<Schema.brand<Schema.NonEmptyString, "GitHubEntityTag">>;
28
- readonly watermark: Schema.OptionFromNullOr<Schema.DateTimeUtcFromString>;
29
- }>, {}>;
30
- /** Efficiency-only REST cursor. Losing it is safe because Event dedup is permanent. */
31
- export declare class PollCursor extends PollCursor_base {
32
- static readonly empty: PollCursor;
33
- }
34
- declare const ChangedIssue_base: Schema.Class<ChangedIssue, Schema.TaggedStruct<"ChangedIssue", {
35
- readonly number: Schema.Int;
36
- readonly updatedAt: Schema.DateTimeUtc;
37
- }>, {}>;
38
- export declare class ChangedIssue extends ChangedIssue_base {
39
- }
40
- declare const ChangedPullRequest_base: Schema.Class<ChangedPullRequest, Schema.TaggedStruct<"ChangedPullRequest", {
41
- readonly number: Schema.Int;
42
- readonly updatedAt: Schema.DateTimeUtc;
43
- }>, {}>;
44
- export declare class ChangedPullRequest extends ChangedPullRequest_base {
45
- }
46
- export declare const ChangedItem: Schema.Union<readonly [typeof ChangedIssue, typeof ChangedPullRequest]>;
47
- export type ChangedItem = typeof ChangedItem.Type;
48
- declare const RepositoryNotModified_base: Schema.Class<RepositoryNotModified, Schema.TaggedStruct<"RepositoryNotModified", {
49
- readonly cursor: typeof PollCursor;
50
- readonly nextPollAt: Schema.Option<Schema.DateTimeUtc>;
51
- }>, {}>;
52
- export declare class RepositoryNotModified extends RepositoryNotModified_base {
53
- }
54
- declare const RepositoryChanges_base: Schema.Class<RepositoryChanges, Schema.TaggedStruct<"RepositoryChanges", {
55
- readonly cursor: typeof PollCursor;
56
- readonly items: Schema.$Array<Schema.Union<readonly [typeof ChangedIssue, typeof ChangedPullRequest]>>;
57
- /** True when the page cap ended the walk early; the rest arrives next cycle. */
58
- readonly backlog: Schema.Boolean;
59
- readonly nextPollAt: Schema.Option<Schema.DateTimeUtc>;
60
- }>, {}>;
61
- export declare class RepositoryChanges extends RepositoryChanges_base {
62
- }
63
- export declare const ChangeDetection: Schema.Union<readonly [typeof RepositoryNotModified, typeof RepositoryChanges]>;
64
- export type ChangeDetection = typeof ChangeDetection.Type;
65
- /** Exact v1 issue payload slice recorded by issue #11. */
2
+ /** The issue payload slice that `if:` expressions and prompt interpolation range over. */
66
3
  export declare const IssuePayload: Schema.Struct<{
67
4
  readonly number: Schema.Int;
68
5
  readonly title: Schema.String;
@@ -154,7 +91,7 @@ export declare const IssuePayload: Schema.Struct<{
154
91
  }, never, never>>, never, never>;
155
92
  }>;
156
93
  export type IssuePayload = typeof IssuePayload.Type;
157
- /** Exact v1 pull-request payload slice recorded by issue #11. */
94
+ /** The pull-request payload slice that `if:` expressions and prompt interpolation range over. */
158
95
  export declare const PullRequestPayload: Schema.Struct<{
159
96
  readonly number: Schema.Int;
160
97
  readonly title: Schema.String;
@@ -336,6 +273,7 @@ export declare const PullRequestPayload: Schema.Struct<{
336
273
  }, never, never>>, never, never>;
337
274
  }>;
338
275
  export type PullRequestPayload = typeof PullRequestPayload.Type;
276
+ /** Identifies an Item's payload content for Event deduplication; timestamp-only changes keep the same hash. */
339
277
  export declare const ContentHash: Schema.brand<Schema.String, "GitHubContentHash">;
340
278
  export type ContentHash = typeof ContentHash.Type;
341
279
  declare const IssueSnapshot_base: Schema.Class<IssueSnapshot, Schema.TaggedStruct<"IssueSnapshot", {
@@ -431,6 +369,7 @@ declare const IssueSnapshot_base: Schema.Class<IssueSnapshot, Schema.TaggedStruc
431
369
  }>;
432
370
  readonly contentHash: Schema.brand<Schema.String, "GitHubContentHash">;
433
371
  }>, {}>;
372
+ /** An issue's observed payload and the content identity used to decide whether it represents new work. */
434
373
  export declare class IssueSnapshot extends IssueSnapshot_base {
435
374
  }
436
375
  declare const PullRequestSnapshot_base: Schema.Class<PullRequestSnapshot, Schema.TaggedStruct<"PullRequestSnapshot", {
@@ -616,9 +555,11 @@ declare const PullRequestSnapshot_base: Schema.Class<PullRequestSnapshot, Schema
616
555
  }>;
617
556
  readonly contentHash: Schema.brand<Schema.String, "GitHubContentHash">;
618
557
  }>, {}>;
558
+ /** A pull request's observed payload and the content identity used to decide whether it represents new work. */
619
559
  export declare class PullRequestSnapshot extends PullRequestSnapshot_base {
620
560
  }
561
+ /** The fetched Item state shared by selection, prompt rendering, and Event deduplication. */
621
562
  export declare const PayloadSnapshot: Schema.Union<readonly [typeof IssueSnapshot, typeof PullRequestSnapshot]>;
622
563
  export type PayloadSnapshot = typeof PayloadSnapshot.Type;
623
564
  export {};
624
- //# sourceMappingURL=model.d.ts.map
565
+ //# sourceMappingURL=payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../src/polling/payload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAgB,MAAM,QAAQ,CAAC;AA8C9C,0FAA0F;AAC1F,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BvB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAC;AAiBpD,iGAAiG;AACjG,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsD7B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,kBAAkB,CAAC,IAAI,CAAC;AAEhE,+GAA+G;AAC/G,eAAO,MAAM,WAAW,kDAEiB,CAAC;AAC1C,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAElD,0GAA0G;AAC1G,qBAAa,aAAc,SAAQ,kBAMlC;CAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEJ,gHAAgH;AAChH,qBAAa,mBAAoB,SAAQ,wBAKvC;CAAG;AAEL,6FAA6F;AAC7F,eAAO,MAAM,eAAe,2EAAqD,CAAC;AAClF,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAC"}
@@ -1,77 +1,13 @@
1
- import { Option, Schema, SchemaGetter } from "effect";
1
+ import { Schema, SchemaGetter } from "effect";
2
2
  const PositiveInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1));
3
3
  const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
4
4
  const Timestamp = Schema.String.check(Schema.isPattern(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/u, {
5
5
  message: "Expected a GitHub UTC timestamp",
6
6
  }));
7
7
  /**
8
- * The payload keys that hold a `Timestamp` above. Bound to the slice schemas:
9
- * a field added to a slice with a `Timestamp` value MUST be listed here, or it
10
- * silently joins the content hash and re-fires every item once (ADR 0007 keeps
11
- * timestamps in the payload but out of the hash).
12
- */
13
- export const TIMESTAMP_FIELDS = new Set([
14
- "closedAt",
15
- "createdAt",
16
- "mergedAt",
17
- "submittedAt",
18
- "updatedAt",
19
- ]);
20
- export const EntityTag = Schema.NonEmptyString.pipe(Schema.brand("GitHubEntityTag"));
21
- export const RepositoryLabelName = Schema.NonEmptyString.pipe(Schema.brand("GitHubRepositoryLabelName"));
22
- /** A complete label catalog and the ETag for its canonical REST URL. */
23
- export class RepositoryLabelCatalog extends Schema.Class("@usine/github/RepositoryLabelCatalog")({
24
- entityTag: Schema.OptionFromNullOr(EntityTag),
25
- labels: Schema.Array(RepositoryLabelName).check(Schema.isUnique()),
26
- }) {
27
- }
28
- /** GitHub confirmed that the catalog named by its ETag has not changed. */
29
- export class RepositoryLabelsNotModified extends Schema.TaggedClass("@usine/github/RepositoryLabelsNotModified")("RepositoryLabelsNotModified", {}) {
30
- }
31
- export const RepositoryLabelDetection = Schema.Union([
32
- RepositoryLabelCatalog,
33
- RepositoryLabelsNotModified,
34
- ]);
35
- /** Efficiency-only REST cursor. Losing it is safe because Event dedup is permanent. */
36
- export class PollCursor extends Schema.Class("@usine/github/PollCursor")({
37
- entityTag: Schema.OptionFromNullOr(EntityTag),
38
- watermark: Schema.OptionFromNullOr(Schema.DateTimeUtcFromString),
39
- }) {
40
- static empty = new PollCursor({
41
- entityTag: Option.none(),
42
- watermark: Option.none(),
43
- });
44
- }
45
- export class ChangedIssue extends Schema.TaggedClass("@usine/github/ChangedIssue")("ChangedIssue", {
46
- number: PositiveInt,
47
- updatedAt: Schema.DateTimeUtc,
48
- }) {
49
- }
50
- export class ChangedPullRequest extends Schema.TaggedClass("@usine/github/ChangedPullRequest")("ChangedPullRequest", {
51
- number: PositiveInt,
52
- updatedAt: Schema.DateTimeUtc,
53
- }) {
54
- }
55
- export const ChangedItem = Schema.Union([ChangedIssue, ChangedPullRequest]);
56
- export class RepositoryNotModified extends Schema.TaggedClass("@usine/github/RepositoryNotModified")("RepositoryNotModified", {
57
- cursor: PollCursor,
58
- nextPollAt: Schema.Option(Schema.DateTimeUtc),
59
- }) {
60
- }
61
- export class RepositoryChanges extends Schema.TaggedClass("@usine/github/RepositoryChanges")("RepositoryChanges", {
62
- cursor: PollCursor,
63
- items: Schema.Array(ChangedItem),
64
- /** True when the page cap ended the walk early; the rest arrives next cycle. */
65
- backlog: Schema.Boolean,
66
- nextPollAt: Schema.Option(Schema.DateTimeUtc),
67
- }) {
68
- }
69
- export const ChangeDetection = Schema.Union([RepositoryNotModified, RepositoryChanges]);
70
- /**
71
- * GitHub declares most GraphQL connections nullable. A null connection and an
72
- * empty one carry the same information, so the boundary normalizes null to
73
- * empty — the domain type (and the CEL environment typed on it) stays
74
- * non-null, and both shapes hash identically.
8
+ * GitHub declares most GraphQL connections nullable, and a null connection means
9
+ * the same as an empty one. Decoding null to empty keeps the payload type
10
+ * non-null and hashes both shapes identically.
75
11
  */
76
12
  const orEmpty = (schema, empty) => Schema.NullOr(schema).pipe(Schema.decodeTo(schema, {
77
13
  decode: SchemaGetter.transform((value) => value ?? empty),
@@ -91,7 +27,7 @@ const IssueComments = Schema.Struct({
91
27
  totalCount: NonNegativeInt,
92
28
  nodes: Schema.Array(IssueComment),
93
29
  });
94
- /** Exact v1 issue payload slice recorded by issue #11. */
30
+ /** The issue payload slice that `if:` expressions and prompt interpolation range over. */
95
31
  export const IssuePayload = Schema.Struct({
96
32
  number: PositiveInt,
97
33
  title: Schema.String,
@@ -118,7 +54,7 @@ export const IssuePayload = Schema.Struct({
118
54
  })),
119
55
  }), emptyConnection),
120
56
  });
121
- /** Null when the reviewer is a deleted user or a mannequin — real content, kept. */
57
+ /** Null when the reviewer is a deleted user or a mannequin. That null is real content and stays in the payload. */
122
58
  const RequestedReviewer = Schema.NullOr(Schema.Struct({ login: Schema.optionalKey(Schema.NonEmptyString) }));
123
59
  const Review = Schema.Struct({
124
60
  author: NullableActor,
@@ -128,7 +64,7 @@ const Review = Schema.Struct({
128
64
  commit: Schema.NullOr(Schema.Struct({ oid: Schema.NonEmptyString })),
129
65
  });
130
66
  const ReviewThreadComment = Schema.Struct({ author: NullableActor, body: Schema.String });
131
- /** Exact v1 pull-request payload slice recorded by issue #11. */
67
+ /** The pull-request payload slice that `if:` expressions and prompt interpolation range over. */
132
68
  export const PullRequestPayload = Schema.Struct({
133
69
  number: PositiveInt,
134
70
  title: Schema.String,
@@ -173,16 +109,20 @@ export const PullRequestPayload = Schema.Struct({
173
109
  nodes: Schema.Array(Schema.Struct({ number: PositiveInt, state: Schema.String })),
174
110
  }), emptyConnection),
175
111
  });
112
+ /** Identifies an Item's payload content for Event deduplication; timestamp-only changes keep the same hash. */
176
113
  export const ContentHash = Schema.String.check(Schema.isPattern(/^[a-f0-9]{64}$/u, { message: "Expected a SHA-256 content hash" })).pipe(Schema.brand("GitHubContentHash"));
114
+ /** An issue's observed payload and the content identity used to decide whether it represents new work. */
177
115
  export class IssueSnapshot extends Schema.TaggedClass("@usine/github/IssueSnapshot")("IssueSnapshot", {
178
116
  payload: IssuePayload,
179
117
  contentHash: ContentHash,
180
118
  }) {
181
119
  }
120
+ /** A pull request's observed payload and the content identity used to decide whether it represents new work. */
182
121
  export class PullRequestSnapshot extends Schema.TaggedClass("@usine/github/PullRequestSnapshot")("PullRequestSnapshot", {
183
122
  payload: PullRequestPayload,
184
123
  contentHash: ContentHash,
185
124
  }) {
186
125
  }
126
+ /** The fetched Item state shared by selection, prompt rendering, and Event deduplication. */
187
127
  export const PayloadSnapshot = Schema.Union([IssueSnapshot, PullRequestSnapshot]);
188
- //# sourceMappingURL=model.js.map
128
+ //# sourceMappingURL=payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload.js","sourceRoot":"","sources":["../../src/polling/payload.ts"],"names":[],"mappings":"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"}
@@ -1,18 +1,24 @@
1
- import { Repository } from "@usine/core";
1
+ import { RepositoryName } from "@usine/core/repository";
2
2
  import { Context, Crypto, Effect, Layer, Option } from "effect";
3
3
  import { HttpClient } from "effect/unstable/http";
4
4
  import { GitHubApp } from "../github-app.ts";
5
- import { type GitHubAppError } from "../model.ts";
6
- import { EntityTag, PollCursor, RepositoryLabelCatalog, RepositoryLabelsNotModified, type ChangeDetection, type ChangedItem, type PayloadSnapshot } from "./model.ts";
5
+ import { type GitHubAppError } from "../error.ts";
6
+ import { EntityTag, PollCursor, type ChangeDetection, type ChangedItem } from "./detection.ts";
7
+ import { type PayloadSnapshot } from "./payload.ts";
8
+ import { RepositoryLabelCatalog, RepositoryLabelsNotModified } from "./labels.ts";
7
9
  declare const GitHubPolling_base: Context.ServiceClass<GitHubPolling, "@usine/github/GitHubPolling", {
8
- readonly changes: (repository: Repository.Name, cursor: PollCursor) => Effect.Effect<ChangeDetection, GitHubAppError>;
9
- readonly labels: (repository: Repository.Name, entityTag: Option.Option<EntityTag>) => Effect.Effect<RepositoryLabelCatalog | RepositoryLabelsNotModified, GitHubAppError>;
10
- readonly snapshot: (repository: Repository.Name, item: ChangedItem) => Effect.Effect<PayloadSnapshot, GitHubAppError>;
10
+ /** Finds issue and PR updates since the saved cursor; persist the returned cursor after processing the detected Items. */
11
+ readonly changes: (repository: RepositoryName, cursor: PollCursor) => Effect.Effect<ChangeDetection, GitHubAppError>;
12
+ /** Reads the repository's label catalog, or confirms the catalog named by `entityTag` is unchanged. */
13
+ readonly labels: (repository: RepositoryName, entityTag: Option.Option<EntityTag>) => Effect.Effect<RepositoryLabelCatalog | RepositoryLabelsNotModified, GitHubAppError>;
14
+ /** Fetches an Item's selection and prompt payload together with its timestamp-independent content hash. */
15
+ readonly snapshot: (repository: RepositoryName, item: ChangedItem) => Effect.Effect<PayloadSnapshot, GitHubAppError>;
11
16
  }>;
12
- /** GitHub change detection and snapshot fetching behind one external seam. */
17
+ /** Finds changed GitHub Items and fetches the snapshots used to select work for Loops. */
13
18
  export declare class GitHubPolling extends GitHubPolling_base {
14
- /** Live GitHub polling adapter over an installation token and Effect HTTP. */
15
19
  static readonly layer: Layer.Layer<GitHubPolling, never, Crypto.Crypto | GitHubApp | HttpClient.HttpClient>;
16
20
  }
17
- export {};
21
+ export { EntityTag, PollCursor, ChangedIssue, ChangedPullRequest, ChangedItem, RepositoryNotModified, RepositoryChanges, ChangeDetection, } from "./detection.ts";
22
+ export { RepositoryLabelName, RepositoryLabelColor, RepositoryLabel, RepositoryLabelCatalog, RepositoryLabelsNotModified, RepositoryLabelDetection, } from "./labels.ts";
23
+ export { ContentHash, IssuePayload, PullRequestPayload, IssueSnapshot, PullRequestSnapshot, PayloadSnapshot, } from "./payload.ts";
18
24
  //# sourceMappingURL=polling.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"polling.d.ts","sourceRoot":"","sources":["../../src/polling/polling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAS,OAAO,EAAE,MAAM,EAAY,MAAM,EAAE,KAAK,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AACzF,OAAO,EAAE,UAAU,EAAyC,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAY7C,OAAO,EAAwB,KAAK,cAAc,EAAwB,MAAM,aAAa,CAAC;AAC9F,OAAO,EAIL,SAAS,EAGT,UAAU,EAGV,sBAAsB,EACtB,2BAA2B,EAK3B,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;;sBAuJE,CAChB,UAAU,EAAE,UAAU,CAAC,IAAI,EAC3B,MAAM,EAAE,UAAU,KACf,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,cAAc,CAAC;qBAClC,CACf,UAAU,EAAE,UAAU,CAAC,IAAI,EAC3B,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAChC,MAAM,CAAC,MAAM,CAAC,sBAAsB,GAAG,2BAA2B,EAAE,cAAc,CAAC;uBACrE,CACjB,UAAU,EAAE,UAAU,CAAC,IAAI,EAC3B,IAAI,EAAE,WAAW,KACd,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,cAAc,CAAC;;AAfvD,8EAA8E;AAC9E,qBAAa,aAAc,SAAQ,kBAgBD;IAChC,8EAA8E;IAC9E,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAChC,aAAa,EACb,KAAK,EACL,MAAM,CAAC,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC,UAAU,CAClD,CAmTC;CACH"}
1
+ {"version":3,"file":"polling.d.ts","sourceRoot":"","sources":["../../src/polling/polling.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAuB,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAS,OAAO,EAAE,MAAM,EAAY,MAAM,EAAE,KAAK,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AACzF,OAAO,EAAE,UAAU,EAAyC,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAY7C,OAAO,EAAwB,KAAK,cAAc,EAAwB,MAAM,aAAa,CAAC;AAC9F,OAAO,EAGL,SAAS,EACT,UAAU,EAGV,KAAK,eAAe,EACpB,KAAK,WAAW,EACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAML,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,sBAAsB,EAEtB,2BAA2B,EAE5B,MAAM,aAAa,CAAC;;IAkJjB,0HAA0H;sBACxG,CAChB,UAAU,EAAE,cAAc,EAC1B,MAAM,EAAE,UAAU,KACf,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,cAAc,CAAC;IACnD,uGAAuG;qBACtF,CACf,UAAU,EAAE,cAAc,EAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAChC,MAAM,CAAC,MAAM,CAAC,sBAAsB,GAAG,2BAA2B,EAAE,cAAc,CAAC;IACxF,2GAA2G;uBACxF,CACjB,UAAU,EAAE,cAAc,EAC1B,IAAI,EAAE,WAAW,KACd,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,cAAc,CAAC;;AAlBvD,0FAA0F;AAC1F,qBAAa,aAAc,SAAQ,kBAmBD;IAChC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAChC,aAAa,EACb,KAAK,EACL,MAAM,CAAC,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC,UAAU,CAClD,CAsTC;CACH;AAED,OAAO,EACL,SAAS,EACT,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,sBAAsB,EACtB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,eAAe,GAChB,MAAM,cAAc,CAAC"}
@@ -1,18 +1,21 @@
1
- import { Repository } from "@usine/core";
1
+ import { canonicalContent } from "./content.js";
2
+ import { RepositoryName, splitRepositoryName } from "@usine/core/repository";
2
3
  import { Clock, Context, Crypto, DateTime, Effect, Layer, Option, Schema } from "effect";
3
4
  import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http";
4
5
  import { GitHubApp } from "../github-app.js";
5
6
  import { API_ROOT, authorized, invalidResponse, pollIntervalMillis, rateLimitResetMillis, rateLimitRetryEpoch, retryAfterMillis, statusError, transportError, } from "../http.js";
6
- import { GitHubRateLimitError } from "../model.js";
7
- import { ChangedIssue, ChangedPullRequest, ContentHash, EntityTag, IssuePayload, IssueSnapshot, PollCursor, PullRequestPayload, PullRequestSnapshot, RepositoryLabelCatalog, RepositoryLabelsNotModified, RepositoryLabelName, RepositoryChanges, RepositoryNotModified, TIMESTAMP_FIELDS, } from "./model.js";
7
+ import { GitHubRateLimitError } from "../error.js";
8
+ import { ChangedIssue, ChangedPullRequest, EntityTag, PollCursor, RepositoryChanges, RepositoryNotModified, } from "./detection.js";
9
+ import { ContentHash, IssuePayload, IssueSnapshot, PullRequestPayload, PullRequestSnapshot, } from "./payload.js";
10
+ import { RepositoryLabel, RepositoryLabelCatalog, RepositoryLabelColor, RepositoryLabelsNotModified, RepositoryLabelName, } from "./labels.js";
8
11
  import { ISSUE_PAYLOAD_QUERY, PULL_REQUEST_PAYLOAD_QUERY } from "./queries.js";
9
12
  const WATERMARK_OVERLAP_MS = 5_000;
10
13
  const RATE_LIMIT_PRESSURE_THRESHOLD = 100;
11
- /** Bounds one cycle's REST walk; the watermark resumes the remainder next cycle. */
14
+ /** Caps one cycle's REST walk. The watermark resumes the remainder next cycle. */
12
15
  const MAX_CHANGE_PAGES = 10;
13
- /** A pathological catalog cannot turn one repository poll into an unbounded walk. */
16
+ /** Caps one repository's label walk so a pathological catalog cannot run unbounded. */
14
17
  const MAX_LABEL_PAGES = 100;
15
- /** GraphQL rate limiting sometimes omits reset headers; wait at least this long. */
18
+ /** GraphQL rate limiting sometimes omits reset headers. Wait at least this long then. */
16
19
  const GRAPHQL_RATE_LIMIT_FALLBACK_MS = 60_000;
17
20
  const RestChangedItem = Schema.Struct({
18
21
  number: Schema.Int.check(Schema.isGreaterThanOrEqualTo(1)),
@@ -20,8 +23,13 @@ const RestChangedItem = Schema.Struct({
20
23
  pullRequest: Schema.optionalKey(Schema.Unknown),
21
24
  }).pipe(Schema.encodeKeys({ updatedAt: "updated_at", pullRequest: "pull_request" }));
22
25
  const RestChangedItems = Schema.Array(RestChangedItem);
23
- const RestRepositoryLabels = Schema.Array(Schema.Struct({ name: RepositoryLabelName }));
24
- /** The GraphQL transport envelope; `errors` arrives on HTTP 200 and must be read. */
26
+ const RestRepositoryLabels = Schema.Array(Schema.Struct({
27
+ name: RepositoryLabelName,
28
+ color: RepositoryLabelColor,
29
+ description: Schema.NullOr(Schema.String),
30
+ }));
31
+ const catalogLabel = ({ name, color, description, }) => new RepositoryLabel({ name, color, description: Option.fromNullishOr(description) });
32
+ /** The GraphQL transport envelope. `errors` arrives on HTTP 200 and must be read. */
25
33
  const GraphqlEnvelope = Schema.Struct({
26
34
  data: Schema.optionalKey(Schema.Unknown),
27
35
  errors: Schema.optionalKey(Schema.Array(Schema.Struct({
@@ -35,17 +43,6 @@ const IssueData = Schema.Struct({
35
43
  const PullRequestData = Schema.Struct({
36
44
  repository: Schema.OptionFromNullOr(Schema.Struct({ pullRequest: Schema.OptionFromNullOr(PullRequestPayload) })),
37
45
  });
38
- const canonicalContent = (value) => {
39
- if (Array.isArray(value))
40
- return value.map(canonicalContent);
41
- if (Schema.is(Schema.JsonObject)(value)) {
42
- return Object.fromEntries(Object.entries(value)
43
- .filter(([key]) => !TIMESTAMP_FIELDS.has(key))
44
- .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
45
- .map(([key, child]) => [key, canonicalContent(child)]));
46
- }
47
- return value;
48
- };
49
46
  const dateTimeAt = (epochMillis) => DateTime.make(epochMillis);
50
47
  const toChangedItems = (decoded) => decoded.map((item) => item.pullRequest === undefined
51
48
  ? new ChangedIssue({ number: item.number, updatedAt: item.updatedAt })
@@ -56,12 +53,16 @@ const latestDateTime = (candidates) => {
56
53
  return Option.none();
57
54
  return dateTimeAt(Math.max(...epochs));
58
55
  };
56
+ const requestBackoff = (headers, now) => latestDateTime([
57
+ retryAfterMillis(headers["retry-after"], now),
58
+ rateLimitResetMillis(headers, RATE_LIMIT_PRESSURE_THRESHOLD),
59
+ ]);
59
60
  const nextPollAt = (headers, now) => latestDateTime([
60
61
  pollIntervalMillis(headers, now),
61
62
  retryAfterMillis(headers["retry-after"], now),
62
63
  rateLimitResetMillis(headers, RATE_LIMIT_PRESSURE_THRESHOLD),
63
64
  ]);
64
- /** `<https://...>; rel="next"` from a Link header, when GitHub has more pages. */
65
+ /** The `rel="next"` URL from a Link header when GitHub has more pages. */
65
66
  const nextPageUrl = (link) => {
66
67
  if (link === undefined)
67
68
  return Option.none();
@@ -73,7 +74,7 @@ const sinceParameter = (watermark) => {
73
74
  return `${new Date(epoch - (epoch % 1_000)).toISOString().slice(0, 19)}Z`;
74
75
  };
75
76
  const changesUrl = (repository, cursor) => {
76
- const { name, owner } = Repository.parts(repository);
77
+ const { name, owner } = splitRepositoryName(repository);
77
78
  const url = new URL(`${API_ROOT}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/issues`);
78
79
  url.searchParams.set("state", "all");
79
80
  url.searchParams.set("sort", "updated");
@@ -85,13 +86,13 @@ const changesUrl = (repository, cursor) => {
85
86
  return url.toString();
86
87
  };
87
88
  const labelsUrl = (repository) => {
88
- const { name, owner } = Repository.parts(repository);
89
+ const { name, owner } = splitRepositoryName(repository);
89
90
  const url = new URL(`${API_ROOT}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/labels`);
90
91
  url.searchParams.set("per_page", "100");
91
92
  return url.toString();
92
93
  };
93
94
  const itemLabelsUrl = (repository, item) => {
94
- const { name, owner } = Repository.parts(repository);
95
+ const { name, owner } = splitRepositoryName(repository);
95
96
  const url = new URL(`${API_ROOT}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/issues/${item}/labels`);
96
97
  url.searchParams.set("per_page", "100");
97
98
  return url.toString();
@@ -103,16 +104,8 @@ const newerWatermark = (cursor, items) => {
103
104
  }
104
105
  return epochs.length === 0 ? Option.none() : dateTimeAt(Math.max(...epochs));
105
106
  };
106
- const makeContentHash = (crypto) => Effect.fn("GitHubPolling.contentHash")(function* (payload) {
107
- const encoded = new TextEncoder().encode(JSON.stringify(canonicalContent(payload)));
108
- // An in-memory SHA-256 digest cannot fail for expected reasons: a failure
109
- // here is a violated platform invariant, not a domain failure.
110
- const digest = yield* crypto.digest("SHA-256", encoded).pipe(Effect.orDie);
111
- return ContentHash.make(Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join(""));
112
- });
113
- /** GitHub change detection and snapshot fetching behind one external seam. */
107
+ /** Finds changed GitHub Items and fetches the snapshots used to select work for Loops. */
114
108
  export class GitHubPolling extends Context.Service()("@usine/github/GitHubPolling") {
115
- /** Live GitHub polling adapter over an installation token and Effect HTTP. */
116
109
  static layer = Layer.effect(GitHubPolling, Effect.gen(function* () {
117
110
  const app = yield* GitHubApp;
118
111
  const crypto = yield* Crypto.Crypto;
@@ -147,11 +140,11 @@ export class GitHubPolling extends Context.Service()("@usine/github/GitHubPollin
147
140
  }
148
141
  const decoded = yield* HttpClientResponse.schemaBodyJson(RestRepositoryLabels)(response).pipe(Effect.mapError((error) => invalidResponse(operation, error.message)));
149
142
  return {
150
- labels: decoded.map(({ name }) => name),
143
+ labels: decoded.map(catalogLabel),
151
144
  next: nextPageUrl(response.headers.link),
152
145
  };
153
146
  });
154
- /** Walks the pages after an already-fetched first one; one cap for every label walk. */
147
+ /** Walks the label pages after an already-fetched first page, under the label page cap. */
155
148
  const remainingLabelPages = Effect.fn("GitHubPolling.remainingLabelPages")(function* (operation, firstPage) {
156
149
  const catalog = [...firstPage.labels];
157
150
  let next = firstPage.next;
@@ -165,7 +158,7 @@ export class GitHubPolling extends Context.Service()("@usine/github/GitHubPollin
165
158
  if (Option.isSome(next)) {
166
159
  return yield* invalidResponse(operation, `GitHub label list exceeded ${MAX_LABEL_PAGES} pages`);
167
160
  }
168
- return catalog.sort((left, right) => left.localeCompare(right));
161
+ return catalog.sort((left, right) => left.name.localeCompare(right.name));
169
162
  });
170
163
  const allLabels = Effect.fn("GitHubPolling.allLabels")(function* (operation, initialUrl) {
171
164
  return yield* remainingLabelPages(operation, yield* labelsPage(operation, initialUrl));
@@ -186,7 +179,7 @@ export class GitHubPolling extends Context.Service()("@usine/github/GitHubPollin
186
179
  }
187
180
  const firstPage = yield* HttpClientResponse.schemaBodyJson(RestRepositoryLabels)(response).pipe(Effect.mapError((error) => invalidResponse("list-repository-labels", error.message)));
188
181
  const catalog = yield* remainingLabelPages("list-repository-labels", {
189
- labels: firstPage.map(({ name }) => name),
182
+ labels: firstPage.map(catalogLabel),
190
183
  next: nextPageUrl(response.headers.link),
191
184
  });
192
185
  const catalogEntityTag = Schema.decodeUnknownOption(EntityTag)(response.headers.etag);
@@ -207,16 +200,19 @@ export class GitHubPolling extends Context.Service()("@usine/github/GitHubPollin
207
200
  const now = yield* Clock.currentTimeMillis;
208
201
  const recommended = nextPollAt(response.headers, now);
209
202
  if (response.status === 304) {
210
- return new RepositoryNotModified({ cursor, nextPollAt: recommended });
203
+ return new RepositoryNotModified({
204
+ cursor,
205
+ nextPollAt: recommended,
206
+ backoffUntil: requestBackoff(response.headers, now),
207
+ });
211
208
  }
212
209
  if (response.status !== 200) {
213
210
  return yield* statusError("poll-repository-changes", response, now);
214
211
  }
215
212
  const decoded = yield* HttpClientResponse.schemaBodyJson(RestChangedItems)(response).pipe(Effect.mapError((error) => invalidResponse("poll-repository-changes", error.message)));
216
213
  const items = toChangedItems(decoded);
217
- // The ETag is efficiency-only: a page without one costs conditional
218
- // requests next cycle, never correctness. Only the first page's tag
219
- // matches the canonical URL the next cycle re-requests.
214
+ // The ETag is efficiency only: a page without one costs conditional requests next cycle, never correctness.
215
+ // Only the first page's tag matches the canonical URL the next cycle re-requests.
220
216
  const entityTag = Schema.decodeUnknownOption(EntityTag)(response.headers.etag);
221
217
  if (Option.isNone(entityTag)) {
222
218
  yield* Effect.logWarning("GitHub omitted the changes ETag; next poll is unconditional", {
@@ -245,19 +241,19 @@ export class GitHubPolling extends Context.Service()("@usine/github/GitHubPollin
245
241
  items: allItems,
246
242
  backlog,
247
243
  nextPollAt: recommended,
244
+ backoffUntil: requestBackoff(response.headers, now),
248
245
  });
249
246
  });
250
247
  const graphql = Effect.fn("GitHubPolling.graphql")(function* (operation, repository, number, query, dataSchema) {
251
248
  const token = yield* app.installationToken();
252
- const { name, owner } = Repository.parts(repository);
249
+ const { name, owner } = splitRepositoryName(repository);
253
250
  const request = HttpClientRequest.post(`${API_ROOT}/graphql`).pipe(HttpClientRequest.bodyJsonUnsafe({ query, variables: { owner, name, number } }), authorized(token.value));
254
251
  const response = yield* execute(operation, request);
255
252
  const now = yield* Clock.currentTimeMillis;
256
253
  if (response.status !== 200)
257
254
  return yield* statusError(operation, response, now);
258
255
  const envelope = yield* HttpClientResponse.schemaBodyJson(GraphqlEnvelope)(response).pipe(Effect.mapError((error) => invalidResponse(operation, error.message)));
259
- // GraphQL reports failures on HTTP 200: rate limiting becomes a typed
260
- // wait; anything else keeps its messages for diagnosis.
256
+ // GraphQL reports failures on HTTP 200. Rate limiting becomes a typed wait, and anything else keeps its messages for diagnosis.
261
257
  if (envelope.errors !== undefined && envelope.errors.length > 0) {
262
258
  const rateLimited = envelope.errors.some((error) => error.type === "RATE_LIMITED");
263
259
  if (rateLimited) {
@@ -283,7 +279,7 @@ export class GitHubPolling extends Context.Service()("@usine/github/GitHubPollin
283
279
  totalLabels: payload.labels.totalCount,
284
280
  });
285
281
  const names = yield* allLabels("fetch-item-labels", itemLabelsUrl(repository, item.number));
286
- return { totalCount: names.length, nodes: names.map((name) => ({ name })) };
282
+ return { totalCount: names.length, nodes: names.map(({ name }) => ({ name })) };
287
283
  });
288
284
  if (item._tag === "ChangedIssue") {
289
285
  const data = yield* graphql("fetch-issue-snapshot", repository, item.number, ISSUE_PAYLOAD_QUERY, IssueData);
@@ -317,4 +313,13 @@ export class GitHubPolling extends Context.Service()("@usine/github/GitHubPollin
317
313
  return { changes, labels, snapshot };
318
314
  }));
319
315
  }
316
+ export { EntityTag, PollCursor, ChangedIssue, ChangedPullRequest, ChangedItem, RepositoryNotModified, RepositoryChanges, ChangeDetection, } from "./detection.js";
317
+ export { RepositoryLabelName, RepositoryLabelColor, RepositoryLabel, RepositoryLabelCatalog, RepositoryLabelsNotModified, RepositoryLabelDetection, } from "./labels.js";
318
+ export { ContentHash, IssuePayload, PullRequestPayload, IssueSnapshot, PullRequestSnapshot, PayloadSnapshot, } from "./payload.js";
319
+ const makeContentHash = (crypto) => Effect.fn("GitHubPolling.contentHash")(function* (payload) {
320
+ const encoded = new TextEncoder().encode(JSON.stringify(canonicalContent(payload)));
321
+ // An in-memory SHA-256 digest fails only on a broken platform, so a failure here is a defect.
322
+ const digest = yield* crypto.digest("SHA-256", encoded).pipe(Effect.orDie);
323
+ return ContentHash.make(Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join(""));
324
+ });
320
325
  //# sourceMappingURL=polling.js.map