sporades 0.9.1 → 0.9.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/CHANGES.md +55 -2
  2. package/README.md +39 -3
  3. package/bin/sporades-host-helper.js +19 -1
  4. package/bin/sporades.js +3348 -276
  5. package/dist/cli/cli-version.d.ts +1 -1
  6. package/dist/cli/cli-version.js +1 -1
  7. package/dist/cli/sporades.js +17 -2
  8. package/dist/cli/sporades.js.map +1 -1
  9. package/dist/client.d.ts +1 -0
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +1 -0
  12. package/dist/client.js.map +1 -1
  13. package/dist/database-runtime.d.ts.map +1 -1
  14. package/dist/database-runtime.js +4 -0
  15. package/dist/database-runtime.js.map +1 -1
  16. package/dist/generated-source-manifest.json +38 -2
  17. package/dist/jobs-runtime.d.ts +21 -0
  18. package/dist/jobs-runtime.d.ts.map +1 -1
  19. package/dist/jobs-runtime.js +375 -14
  20. package/dist/jobs-runtime.js.map +1 -1
  21. package/dist/server-runtime-source.d.ts +4 -1
  22. package/dist/server-runtime-source.d.ts.map +1 -1
  23. package/dist/server-runtime-source.js +571 -20
  24. package/dist/server-runtime-source.js.map +1 -1
  25. package/dist/server.d.ts +13 -1
  26. package/dist/server.d.ts.map +1 -1
  27. package/dist/server.js +23 -8
  28. package/dist/server.js.map +1 -1
  29. package/dist/stripe-team-billing-provider.d.ts +33 -0
  30. package/dist/stripe-team-billing-provider.d.ts.map +1 -0
  31. package/dist/stripe-team-billing-provider.js +564 -0
  32. package/dist/stripe-team-billing-provider.js.map +1 -0
  33. package/dist/team-billing-convergence.d.ts +7 -0
  34. package/dist/team-billing-convergence.d.ts.map +1 -0
  35. package/dist/team-billing-convergence.js +359 -0
  36. package/dist/team-billing-convergence.js.map +1 -0
  37. package/dist/team-billing-erasure.d.ts +29 -0
  38. package/dist/team-billing-erasure.d.ts.map +1 -0
  39. package/dist/team-billing-erasure.js +310 -0
  40. package/dist/team-billing-erasure.js.map +1 -0
  41. package/dist/team-billing-import.d.ts +43 -0
  42. package/dist/team-billing-import.d.ts.map +1 -0
  43. package/dist/team-billing-import.js +191 -0
  44. package/dist/team-billing-import.js.map +1 -0
  45. package/dist/team-billing-management.d.ts +48 -0
  46. package/dist/team-billing-management.d.ts.map +1 -0
  47. package/dist/team-billing-management.js +545 -0
  48. package/dist/team-billing-management.js.map +1 -0
  49. package/dist/team-billing-runtime.d.ts +153 -0
  50. package/dist/team-billing-runtime.d.ts.map +1 -0
  51. package/dist/team-billing-runtime.js +1004 -0
  52. package/dist/team-billing-runtime.js.map +1 -0
  53. package/dist/team-billing-subscription-semantics.d.ts +12 -0
  54. package/dist/team-billing-subscription-semantics.d.ts.map +1 -0
  55. package/dist/team-billing-subscription-semantics.js +22 -0
  56. package/dist/team-billing-subscription-semantics.js.map +1 -0
  57. package/dist/teams-runtime.d.ts +3 -0
  58. package/dist/teams-runtime.d.ts.map +1 -1
  59. package/dist/teams-runtime.js +28 -5
  60. package/dist/teams-runtime.js.map +1 -1
  61. package/dist/templates/client-runtime-template.d.ts.map +1 -1
  62. package/dist/templates/client-runtime-template.js +23 -0
  63. package/dist/templates/client-runtime-template.js.map +1 -1
  64. package/dist/templates/scaffold-template.js +7 -2
  65. package/dist/templates/scaffold-template.js.map +1 -1
  66. package/dist/templates/server-bundle-entry.d.ts.map +1 -1
  67. package/dist/templates/server-bundle-entry.js +2 -0
  68. package/dist/templates/server-bundle-entry.js.map +1 -1
  69. package/package.json +5 -1
  70. package/src/types/client.d.ts +47 -0
  71. package/src/types/server.d.ts +110 -4
  72. package/src/types/team-billing-import.d.ts +54 -0
package/CHANGES.md CHANGED
@@ -1,10 +1,64 @@
1
1
  # Changes
2
2
 
3
+ - Expose the verified provider-free Team Billing projection to active Capsule
4
+ query and mutation contexts and to exact-Team Join admission. Current members
5
+ may be authorized for safe reads while all customer-directed commands remain
6
+ current-Team-admin operations; retained context handles are revoked.
7
+ - Add an offline `sporades/server/team-billing-import` seam for exact,
8
+ provider-free import of verified legacy Subscription snapshots and replay
9
+ guards. Incomplete or conflicting evidence fails closed, including drift in
10
+ durable Event ordering, terminal-latch safety fields, and contradictory
11
+ Subscription Event/state tuples. The public adapter type now declares the
12
+ complete named-dialect, execution, prepared-statement, and transaction seam.
13
+
3
14
  ## Unreleased - 2026-08-24
4
15
 
5
16
  Changes since v0.9.0.
6
17
 
7
- No changes detected.
18
+ ### 🚀 Features
19
+
20
+ - Expose verified billing state to capsule policy (946f0736).
21
+ - Add safe legacy Team Billing import seam (dab78ad9).
22
+ - Add provider-safe Team Billing erasure (9d334c0c).
23
+ - Add managed Team Billing convergence (ebdfd265).
24
+ - Add explicitly configured Team Customer Portal (760e5c4d).
25
+ - Add durable headless Team Checkout (4738b0fb).
26
+ - Add headless Team Billing foundation (57670d13).
27
+ - Add atomic Stripe consequence handling (04274543).
28
+
29
+ ### 🐛 Bug Fixes
30
+
31
+ - Prove Stripe test Team Billing lifecycle (2aedbbcb).
32
+ - Fix packed blank Capsule typechecking (1662dd27).
33
+ - Prevent Stripe retention repair starvation (671f9537).
34
+
35
+ ### 📝 Documentation
36
+
37
+ - Clarify private Team billing retention (8db4f2f8).
38
+ - Expose safe Team billing quarantine inspection (0dd71f85).
39
+ - Harden Team billing evidence validation (7b91b311).
40
+ - Converge verified Team billing state atomically (f962d06c).
41
+ - Document unrepresentable Stripe retention (27a852f1).
42
+ - Prove Stripe contention across runtimes (1ed35c38).
43
+ - Preserve cancellation and exact Stripe retention (c8591c52).
44
+ - Defer atomic Stripe fence contention durably (47e93072).
45
+ - Expose Team counts to atomic Stripe consequences (9f43dbe7).
46
+ - Periodically recheck Stripe retention repairs (9e5908e8).
47
+ - Recover classified Stripe retention repairs (f6c853f9).
48
+ - Harden Stripe payload retention cleanup (0b163187).
49
+ - Bound Stripe Event Job payload retention (cf2cf6eb).
50
+ - Harden atomic Stripe consequence recovery (92b55f5d).
51
+
52
+ ### 🧪 Tests
53
+
54
+ - Preserve Team Portal capability across transient reads (7ffba828).
55
+ - Revalidate Team Portal authority at every seam (fcb4380e).
56
+ - Reconcile Checkout state after final lease expiry (c51ab5f7).
57
+ - Terminally settle exhausted Team Checkout retries (6fcb803f).
58
+ - Serialize Team Billing authority with Team lifecycle (987a4750).
59
+ - Validate Team Billing projection semantics (e7f05b20).
60
+ - Fail closed on Team Billing correlation drift (003e24af).
61
+ - Classify near-ceiling Stripe settlement (92cba517).
8
62
 
9
63
  ## 0.8.5 - 2026-08-15
10
64
 
@@ -42,4 +96,3 @@ generated artifacts, and documentation.
42
96
  not select a current Team or automatically partition Capsule data; Sporades
43
97
  never sends Join-link email. See the [Built-in Teams reference](https://mgscox.github.io/sporades/reference/teams).
44
98
 
45
-
package/README.md CHANGED
@@ -58,7 +58,32 @@ sporades host push --restart
58
58
  email-bound Join links, membership application roles, and explicit Team ACL
59
59
  decisions—without a hidden current Team or automatic data partitioning.
60
60
  Trusted `teams.admitJoin` policies may make atomic seat decisions from
61
- read-only app state hidden by the joining user's ordinary row ACLs.
61
+ read-only app state hidden by the joining user's ordinary row ACLs and the
62
+ exact Team's provider-free verified billing projection.
63
+ - **Headless Team Billing, app-rendered**: an optional `teamBilling` declaration
64
+ binds stable product keys to exact sandbox/live Stripe Prices and a fixed or
65
+ accepted-Team-member quantity policy. Sporades rechecks current Team-admin
66
+ authority plus the Capsule's transaction-bound policy on every operation and
67
+ exposes the closed, provider-free `teamBilling.get(teamId)` projection plus
68
+ durable `teamBilling.startCheckout(...)`, `teamBilling.openPortal(...)`, and
69
+ `teamBilling.requestPlanTransition(...)`. Portal owns compatible same-policy
70
+ switches; Sporades manages fixed-to-Team-counted transitions and keeps a
71
+ Team-counted Subscription converged after membership commits.
72
+ `teamBilling.prepareErasure(...)` durably expires or safely resolves every
73
+ issued Checkout and immediately cancels known or newly discovered live
74
+ Subscriptions before a transaction-bound server admission permits the app's
75
+ separate local deletion. Provider-free identity tombstones reject late
76
+ entitlement recreation; the Stripe Customer is not deleted.
77
+ Those commands may return only validated, short-lived Stripe-hosted URL
78
+ capabilities. Verified Checkout, Subscription, and failed-invoice evidence
79
+ converges through runtime-owned semantic ratchets and terminal latches;
80
+ malformed or ambiguous evidence fails closed without exposing provider
81
+ identifiers. The Capsule owns every component, route, message, and
82
+ entitlement decision.
83
+ Offline migration tools can import complete verified legacy snapshots and
84
+ provider-free replay guards through `sporades/server/team-billing-import`;
85
+ the seam performs no provider I/O and rejects incomplete or changed tuples,
86
+ including corrupted durable Event ordering or terminal-latch state.
62
87
  - **Realtime everything**: configuration free - automatic notifications, even for Postgress and AWS-S3
63
88
 
64
89
  ## Documentation
@@ -68,7 +93,8 @@ sporades host push --restart
68
93
  - [Feature reference](https://mgscox.github.io/sporades/guide/reference): exhaustive contracts and
69
94
  command lookup, split into focused topic pages.
70
95
  - [Built-in Teams](https://mgscox.github.io/sporades/reference/teams): collaboration model, Join
71
- links, application roles, and explicit Team ACL decisions.
96
+ links, application roles, explicit Team ACL decisions, and the headless Team
97
+ Billing declaration and safe projection.
72
98
  - [Access-key server and operator reference](https://mgscox.github.io/sporades/reference/server-runtime#gate-handlers-with-requireauth):
73
99
  scoped Bearer admission, user-owned lifecycle, Credential provenance, and
74
100
  the bounded operator CLI.
@@ -169,9 +195,19 @@ Sporades currently includes:
169
195
  retries converge and no Capsule billing state changes automatically. The Job
170
196
  delivers one Verified Stripe event to the blank Capsule's single
171
197
  `stripeEvents: stripeEvent(...)` policy seam under the userless Privileged
172
- audit lifecycle. Generated policy ignores unknown events and tells authors to
198
+ audit lifecycle. Capsules that need one serialized, all-or-nothing database
199
+ consequence can opt into `stripeEvent({ consequence: "atomic" }, handler)`;
200
+ the legacy declaration remains available for cooperative long-lived handlers.
201
+ Generated policy ignores unknown events and tells authors to
173
202
  make deliberate consequences idempotent and order-independent, reject stale
174
203
  later-arriving observations, and avoid logging or retaining raw provider data.
204
+ A successful reserved Stripe Event Job retains its verified payload for 30
205
+ days, then bounded runtime cleanup leaves only the digest-backed terminal
206
+ replay tombstone. Unresolved deliveries retain their retry/repair payload;
207
+ this includes legacy successes with absent or malformed completion timestamps,
208
+ plus canonical near-ceiling settlements whose exact deadline is
209
+ unrepresentable. Safe operator inspection distinguishes those cases without
210
+ exposing provider data.
175
211
  The catalogue owns each Price mode; browser input owns neither mode nor Stripe
176
212
  identity. Existing and non-blank Capsules remain unchanged.
177
213
  - Local Dev sessions with rebuilds, WebSocket reconnects, SQLite persistence,
@@ -177,8 +177,24 @@ var ACCESS_KEY_CLIENT_ADDRESS_HEADER = "x-sporades-client-address";
177
177
  // src/access-keys-runtime.ts
178
178
  var UNKNOWN_ACCESS_KEY_DIGEST = Buffer.from("4f7c77f7b9231094754542ed50fdfd62a2cf24a5e961b61f899b85b6fe33c72b", "hex");
179
179
 
180
+ // src/team-billing-management.ts
181
+ var CLAIM_TTL_MS = 5 * 60 * 1e3;
182
+
183
+ // src/team-billing-convergence.ts
184
+ var RANK = Object.freeze({ active: 20, cancelling: 30, "past-due": 40, cancelled: 50 });
185
+
186
+ // src/team-billing-runtime.ts
187
+ var CHECKOUT_CONTINUATION_TTL_DEFAULT_SECONDS = 10 * 60;
188
+ var CHECKOUT_CONTINUATION_TTL_MAX_SECONDS = 30 * 60;
189
+
190
+ // src/team-billing-erasure.ts
191
+ var CLAIM_TTL_MS2 = 5 * 6e4;
192
+
180
193
  // src/jobs-runtime.ts
181
194
  var nodeCryptoModule = process.getBuiltinModule("node:crypto");
195
+ var STRIPE_EVENT_PAYLOAD_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
196
+ var REDACTED_STRIPE_EVENT_PAYLOAD = JSON.stringify({ kind: "stripe-event", retained: false });
197
+ var STRIPE_EVENT_PAYLOAD_SENTINEL_RECHECK_MS = 24 * 60 * 60 * 1e3;
182
198
  var JOB_AUTH_SNAPSHOT_MAX_BYTES = 8 * 1024;
183
199
  var MAX_JOB_TIMESTAMP_MS = Date.parse("9999-12-31T23:59:59.999Z");
184
200
  var MIN_JOB_TIMESTAMP_MS = Date.parse("0000-01-01T00:00:00.000Z");
@@ -440,6 +456,8 @@ var transactionBeforeCommitChecks2 = Symbol.for("sporades.database.transactionBe
440
456
  // src/server-runtime-source.ts
441
457
  var trustedReadTransactionAdapter = Symbol("sporades.trustedReadTransactionAdapter");
442
458
  var runtimeOwnedJobEnqueueHandler = Symbol("sporades.runtimeOwnedJobEnqueueHandler");
459
+ var atomicStripeEventDefinitionBrand = Symbol.for("sporades.stripeEvent.atomicDefinition");
460
+ var atomicStripeFenceContention = Symbol("sporades.atomicStripeFenceContention");
443
461
  function logPayloadMaxBytes(config = {}) {
444
462
  const configured = Number(config.logs?.payloadMaxBytes ?? config.logging?.payloadMaxBytes);
445
463
  return Number.isInteger(configured) && configured > 0 ? configured : 4096;
@@ -595,7 +613,7 @@ function writeEnvelope(result, failed = false) {
595
613
  }
596
614
 
597
615
  // src/cli/cli-version.ts
598
- var CLI_VERSION = "0.9.1";
616
+ var CLI_VERSION = "0.9.2";
599
617
 
600
618
  // src/cli/schedule-inspection-envelope.ts
601
619
  var SCHEDULE_DIAGNOSTIC_FIELDS = /* @__PURE__ */ new Set([