@particle-academy/fancy-connector-core 0.12.0 → 0.14.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/CHANGELOG.md CHANGED
@@ -6,6 +6,84 @@ All notable changes to `fancy-connector-core` are documented here, in
6
6
  **This package is pre-1.0, so breaking changes land in MINOR releases.** The
7
7
  version number is not a promise it can keep yet; the entries below are.
8
8
 
9
+ ## [0.14.0] - 2026-11-07
10
+
11
+ ### Added
12
+
13
+ - **`readWithCursor` / `CursorRead::read`: a read that resumes from a
14
+ HOST-HELD cursor, and pages.** It's for Gmail's `history.list` after a push,
15
+ and Drive's `changes.list` after a channel notification, where the delivery
16
+ says only that something moved. The package holds no state: the host stores
17
+ the cursor, passes it in, and persists `cursor.next` when the run succeeds.
18
+ - `next` is read ONLY from the LAST page: Gmail's `historyId` is the
19
+ mailbox's current one on every page.
20
+ - More than `page.maxPages` is refused as `cursor-overflow`, never a partial
21
+ read.
22
+ - The provider's `expiredStatus` (Gmail's 404) is refused as
23
+ `cursor-expired`. Every other failure is rethrown unchanged.
24
+ - No stored cursor is refused as `cursor-missing`, and the provider is not
25
+ called.
26
+ - A collected list that's absent is `[]`; one that isn't a list is
27
+ `bad-page`.
28
+ - Cursors are strings.
29
+ - A refusal carries the caller's `resyncQuery`.
30
+
31
+ The reasons ship as data (`CURSOR_READ_REASONS`, `CursorRead::REASONS`).
32
+ Both runtimes read `fixtures/cursor-read/cases.json`: 14 authored cases
33
+ against a scripted provider, every call compared.
34
+
35
+ ### Changed
36
+
37
+ - The README and the npm description now say plainly that PHP apps install
38
+ the package with Composer.
39
+ - `fixtures/jwt` gains rows 0015 to 0024: signature length, values at and
40
+ above the modulus, and valid RSA signatures over malformed PKCS#1 v1.5
41
+ blocks.
42
+
43
+ `CONNECTOR_API_VERSION` is unchanged: everything here is optional.
44
+
45
+ ## [0.13.0] - 2026-11-01
46
+
47
+ ### Added
48
+
49
+ - **`verifyJwt` / `Jwt::verify`: RS256 JWT verification against keys the
50
+ HOST supplies.** The core never fetches a key set. Every rule fails closed:
51
+ RS256 only, with `none` and `HS256` refused by name; a `kid` must name a
52
+ supplied key; `exp` is required and `nbf` honoured, both with 60 s of
53
+ leeway; the audience is REQUIRED unless the caller passes `null` on
54
+ purpose; the issuer is matched when given. Reasons are fixed strings. Both
55
+ runtimes read `fixtures/jwt/cases.json`, led by RFC 7515 Appendix A.2,
56
+ which verifies from the RFC's own inputs.
57
+ - **The `oidc-jwt` verification scheme, for Google Cloud Pub/Sub push**
58
+ (Gmail's `users.watch` notifications). `verifyOidcDelivery` /
59
+ `OidcDelivery::verify`, reached through `verifyDelivery`'s new optional
60
+ fifth argument, an `OidcExpectation` (`keys`, `audience`, `principal`, all
61
+ the host's). It refuses every push when any of the three is unconfigured,
62
+ reads `Bearer <token>` case-insensitively, verifies the JWT, then requires
63
+ the scheme's `principalClaim` (`email`) to EQUAL the configured service
64
+ account and its `verifiedClaim` (`email_verified`) to be the literal
65
+ `true`. The principal check is what stops a stranger's push subscription,
66
+ aimed at your URL with your URL as its audience, whose token Google signs
67
+ correctly. `fixtures/oidc-delivery/cases.json` has 19 authored rows.
68
+ - **The `pubsub-push` decode kind.** `decodePubSubPush` /
69
+ `PubSubPush::decode`, also through `decodeDelivery` /
70
+ `DeliveryDecode::apply`. It unwraps Pub/Sub's push envelope to
71
+ `{subscription, messageId, publishTime, attributes, deliveryAttempt, data}`.
72
+ `data` may be in either base64 alphabet, padded or not, and is parsed as
73
+ JSON. Malformed input is refused BY NAME: `not-json`, `missing-message`,
74
+ `missing-data`, `bad-encoding` or `data-not-json`. Held to the 13-case
75
+ corpus under `fixtures/pubsub-push/`.
76
+
77
+ ### Changed
78
+
79
+ - `DeliveryDecode` (TS) is now a union,
80
+ `{kind: "form-field-json", field} | {kind: "pubsub-push"}`, and
81
+ `DELIVERY_DECODE_KINDS` / `DeliveryDecode::KINDS` gain `"pubsub-push"`. A
82
+ declaration written as a literal is unaffected. Code that reads `.field` off
83
+ a `DeliveryDecode` it did not construct must narrow on `kind` first.
84
+
85
+ `CONNECTOR_API_VERSION` is unchanged: everything here is optional.
86
+
9
87
  ## [0.12.0] - 2026-11-01
10
88
 
11
89
  ### Added
package/README.md CHANGED
@@ -9,10 +9,15 @@ versioned rendering, chain posting, declared metric shapes, credential-free
9
9
  probes, and API-drift reporting.
10
10
 
11
11
  Matched **TypeScript + PHP**, one repository, **zero runtime dependencies in
12
- either ecosystem**.
12
+ either ecosystem**. TypeScript and Node apps install it from npm; **PHP apps
13
+ (Laravel included) install it with Composer**. Both packages are released
14
+ together at the same version.
13
15
 
14
16
  ```bash
17
+ # TypeScript / Node
15
18
  npm install @particle-academy/fancy-connector-core
19
+
20
+ # PHP (Composer)
16
21
  composer require particle-academy/fancy-connector-core
17
22
  ```
18
23