@o3co/auth-provider-templates 0.0.0 → 0.18.0-rc.1

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/LICENSE +201 -0
  2. package/README.md +2 -3
  3. package/authorize-store/README.md +3 -0
  4. package/authorize-store/src/module.d.ts +2 -0
  5. package/authorize-store/src/module.js +19 -0
  6. package/client-assertion-store/README.md +3 -0
  7. package/client-assertion-store/src/module.d.ts +2 -0
  8. package/client-assertion-store/src/module.js +22 -0
  9. package/code-grant-store/README.md +3 -0
  10. package/code-grant-store/src/module.d.ts +2 -0
  11. package/code-grant-store/src/module.js +36 -0
  12. package/code-grant-store/src/section.d.ts +6 -0
  13. package/code-grant-store/src/section.js +18 -0
  14. package/consent-store/README.md +3 -0
  15. package/consent-store/src/module.d.ts +2 -0
  16. package/consent-store/src/module.js +34 -0
  17. package/device-grant-store/README.md +3 -0
  18. package/device-grant-store/src/module.d.ts +2 -0
  19. package/device-grant-store/src/module.js +33 -0
  20. package/dpop-store/README.md +3 -0
  21. package/dpop-store/src/module.d.ts +2 -0
  22. package/dpop-store/src/module.js +19 -0
  23. package/federation-grants-store/README.md +3 -0
  24. package/federation-grants-store/src/module.d.ts +2 -0
  25. package/federation-grants-store/src/module.js +91 -0
  26. package/federation-grants-store/src/section.d.ts +6 -0
  27. package/federation-grants-store/src/section.js +18 -0
  28. package/federation-store/README.md +3 -0
  29. package/federation-store/src/module.d.ts +2 -0
  30. package/federation-store/src/module.js +21 -0
  31. package/federation-tokens-store/README.md +3 -0
  32. package/federation-tokens-store/src/module.d.ts +2 -0
  33. package/federation-tokens-store/src/module.js +43 -0
  34. package/mfa-flows-store/README.md +3 -0
  35. package/mfa-flows-store/src/module.d.ts +2 -0
  36. package/mfa-flows-store/src/module.js +23 -0
  37. package/mfa-store/README.md +3 -0
  38. package/mfa-store/src/module.d.ts +2 -0
  39. package/mfa-store/src/module.js +24 -0
  40. package/package.json +95 -3
  41. package/refresh-store/README.md +3 -0
  42. package/refresh-store/src/module.d.ts +2 -0
  43. package/refresh-store/src/module.js +60 -0
  44. package/refresh-store/src/section.d.ts +8 -0
  45. package/refresh-store/src/section.js +32 -0
  46. package/rp-logout-store/README.md +3 -0
  47. package/rp-logout-store/src/module.d.ts +2 -0
  48. package/rp-logout-store/src/module.js +39 -0
  49. package/rp-logout-store/src/section.d.ts +7 -0
  50. package/rp-logout-store/src/section.js +25 -0
  51. package/session-store/README.md +3 -0
  52. package/session-store/src/module.d.ts +2 -0
  53. package/session-store/src/module.js +65 -0
  54. package/session-store/src/section.d.ts +7 -0
  55. package/session-store/src/section.js +25 -0
  56. package/session-tokens-store/README.md +3 -0
  57. package/session-tokens-store/src/module.d.ts +2 -0
  58. package/session-tokens-store/src/module.js +55 -0
  59. package/session-tokens-store/src/section.d.ts +7 -0
  60. package/session-tokens-store/src/section.js +25 -0
  61. package/subject-revocation-store/README.md +3 -0
  62. package/subject-revocation-store/src/module.d.ts +2 -0
  63. package/subject-revocation-store/src/module.js +26 -0
  64. package/tokens-store/README.md +3 -0
  65. package/tokens-store/src/module.d.ts +2 -0
  66. package/tokens-store/src/module.js +22 -0
  67. package/users-store/README.md +3 -0
  68. package/users-store/src/module.d.ts +2 -0
  69. package/users-store/src/module.js +44 -0
  70. package/webauthn-store/README.md +3 -0
  71. package/webauthn-store/src/module.d.ts +2 -0
  72. package/webauthn-store/src/module.js +50 -0
@@ -0,0 +1,43 @@
1
+ import { refreshLocks, upstreamTokenStore, } from "@o3co/auth-provider-upstream-login/federation-tokens";
2
+ import { defineModule } from "@o3co/auth-provider-foundation/kernel";
3
+ import { recordsIn } from "@o3co/auth-provider-foundation/records";
4
+ import { spaces, store } from "@o3co/auth-provider-foundation/store";
5
+ /** Each need federation-tokens states for its records, as the guarantee a space declares for it. */
6
+ const tokensGuaranteeFor = {
7
+ neverEvicted: "no-eviction",
8
+ survivesFailover: "replicated",
9
+ };
10
+ /** Each need it states for its locks. */
11
+ const locksGuaranteeFor = {
12
+ neverEvicted: "no-eviction",
13
+ };
14
+ const tokens = {
15
+ name: "federation-tokens-store.tokens",
16
+ guarantees: Object.values(tokensGuaranteeFor),
17
+ };
18
+ const locks = {
19
+ name: "federation-tokens-store.locks",
20
+ guarantees: Object.values(locksGuaranteeFor),
21
+ };
22
+ export default defineModule({ name: "federation-tokens-store" }, (m) => [
23
+ m.contribute(spaces).by(() => tokens),
24
+ m.contribute(spaces).by(() => locks),
25
+ m.provide(upstreamTokenStore).by(async (c) => {
26
+ const place = { store: await c.get(store), space: tokens, log: c.log, random: c.random };
27
+ const records = recordsIn(place);
28
+ return {
29
+ save: records.create,
30
+ read: records.read,
31
+ update: records.change,
32
+ remove: records.remove,
33
+ };
34
+ }),
35
+ m.provide(refreshLocks).by(async (c) => {
36
+ const place = { store: await c.get(store), space: locks, log: c.log, random: c.random };
37
+ const marked = recordsIn(place);
38
+ return {
39
+ hold: (name, mark, lifetimeMs) => marked.create(name, mark, lifetimeMs),
40
+ update: marked.change,
41
+ };
42
+ }),
43
+ ]);
@@ -0,0 +1,3 @@
1
+ # mfa-flows-store
2
+
3
+ Wires `mfa-flows`' store interface, transactions, to `records`' records under a secret, so a transaction's identifier never reaches the store. Its one space declares a guarantee for each of the other needs `mfa-flows` states. A need with nothing mapped to it fails the type check, and `mfa-flows`' store contract, run on a store that loses what a missing guarantee allows, checks what each guarantee means. The wiring only maps, with no branches or loops. Depends on `kernel`, `mfa-flows`, `records` and `store`.
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@o3co/auth-provider-foundation/kernel").Module;
2
+ export default _default;
@@ -0,0 +1,23 @@
1
+ import { defineModule } from "@o3co/auth-provider-foundation/kernel";
2
+ import { transactionStore, } from "@o3co/auth-provider-second-factor/mfa-flows";
3
+ import { secretRecordsIn } from "@o3co/auth-provider-foundation/records";
4
+ import { spaces, store } from "@o3co/auth-provider-foundation/store";
5
+ /** Each need mfa-flows states, as what meets it: a guarantee its space declares, or records under a secret. */
6
+ const { namesFromSecret: recordsFor, ...guaranteeFor } = {
7
+ neverEvicted: "no-eviction",
8
+ survivesCrash: "durable",
9
+ survivesFailover: "replicated",
10
+ namesFromSecret: secretRecordsIn,
11
+ };
12
+ const transactions = {
13
+ name: "mfa-flows-store.transactions",
14
+ guarantees: Object.values(guaranteeFor),
15
+ };
16
+ export default defineModule({ name: "mfa-flows-store" }, (m) => [
17
+ m.contribute(spaces).by(() => transactions),
18
+ m.provide(transactionStore).by(async (c) => {
19
+ const place = { store: await c.get(store), space: transactions, log: c.log, random: c.random };
20
+ const records = recordsFor(place);
21
+ return { save: records.create, read: records.read, update: records.change };
22
+ }),
23
+ ]);
@@ -0,0 +1,3 @@
1
+ # mfa-store
2
+
3
+ Wires `mfa`'s store interface, factor lists, to `records`' records, kept without end. Its one space declares a guarantee for each need `mfa` states. A need with nothing mapped to it fails the type check, and `mfa`'s store contract, run on a store that loses what a missing guarantee allows, checks what each guarantee means. The wiring only maps, with no branches or loops. Depends on `kernel`, `mfa`, `records` and `store`.
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@o3co/auth-provider-foundation/kernel").Module;
2
+ export default _default;
@@ -0,0 +1,24 @@
1
+ import { defineModule } from "@o3co/auth-provider-foundation/kernel";
2
+ import { factorStore } from "@o3co/auth-provider-second-factor/mfa";
3
+ import { recordsIn } from "@o3co/auth-provider-foundation/records";
4
+ import { spaces, store } from "@o3co/auth-provider-foundation/store";
5
+ /** Each need mfa states, as the guarantee a space declares for it. */
6
+ const guaranteeFor = {
7
+ neverEvicted: "no-eviction",
8
+ survivesCrash: "durable",
9
+ survivesFailover: "replicated",
10
+ confirmedReads: "confirmed-reads",
11
+ };
12
+ const factors = { name: "mfa-store.factors", guarantees: Object.values(guaranteeFor) };
13
+ export default defineModule({ name: "mfa-store" }, (m) => [
14
+ m.contribute(spaces).by(() => factors),
15
+ m.provide(factorStore).by(async (c) => {
16
+ const place = { store: await c.get(store), space: factors, log: c.log, random: c.random };
17
+ const records = recordsIn(place);
18
+ return {
19
+ save: (key, record) => records.create(key, record, "endless"),
20
+ read: records.read,
21
+ update: records.change,
22
+ };
23
+ }),
24
+ ]);
package/package.json CHANGED
@@ -1,10 +1,102 @@
1
1
  {
2
2
  "name": "@o3co/auth-provider-templates",
3
- "version": "0.0.0",
3
+ "version": "0.18.0-rc.1",
4
+ "type": "module",
4
5
  "license": "Apache-2.0",
5
6
  "repository": {
6
7
  "type": "git",
7
- "url": "git+https://github.com/o3co/auth.provider.git",
8
+ "url": "https://github.com/o3co/auth.provider",
8
9
  "directory": "modules/templates"
10
+ },
11
+ "engines": {
12
+ "node": ">=24"
13
+ },
14
+ "exports": {
15
+ "./authorize-store/module": {
16
+ "types": "./authorize-store/src/module.d.ts",
17
+ "default": "./authorize-store/src/module.js"
18
+ },
19
+ "./client-assertion-store/module": {
20
+ "types": "./client-assertion-store/src/module.d.ts",
21
+ "default": "./client-assertion-store/src/module.js"
22
+ },
23
+ "./code-grant-store/module": {
24
+ "types": "./code-grant-store/src/module.d.ts",
25
+ "default": "./code-grant-store/src/module.js"
26
+ },
27
+ "./consent-store/module": {
28
+ "types": "./consent-store/src/module.d.ts",
29
+ "default": "./consent-store/src/module.js"
30
+ },
31
+ "./device-grant-store/module": {
32
+ "types": "./device-grant-store/src/module.d.ts",
33
+ "default": "./device-grant-store/src/module.js"
34
+ },
35
+ "./dpop-store/module": {
36
+ "types": "./dpop-store/src/module.d.ts",
37
+ "default": "./dpop-store/src/module.js"
38
+ },
39
+ "./federation-grants-store/module": {
40
+ "types": "./federation-grants-store/src/module.d.ts",
41
+ "default": "./federation-grants-store/src/module.js"
42
+ },
43
+ "./federation-store/module": {
44
+ "types": "./federation-store/src/module.d.ts",
45
+ "default": "./federation-store/src/module.js"
46
+ },
47
+ "./federation-tokens-store/module": {
48
+ "types": "./federation-tokens-store/src/module.d.ts",
49
+ "default": "./federation-tokens-store/src/module.js"
50
+ },
51
+ "./mfa-flows-store/module": {
52
+ "types": "./mfa-flows-store/src/module.d.ts",
53
+ "default": "./mfa-flows-store/src/module.js"
54
+ },
55
+ "./mfa-store/module": {
56
+ "types": "./mfa-store/src/module.d.ts",
57
+ "default": "./mfa-store/src/module.js"
58
+ },
59
+ "./refresh-store/module": {
60
+ "types": "./refresh-store/src/module.d.ts",
61
+ "default": "./refresh-store/src/module.js"
62
+ },
63
+ "./rp-logout-store/module": {
64
+ "types": "./rp-logout-store/src/module.d.ts",
65
+ "default": "./rp-logout-store/src/module.js"
66
+ },
67
+ "./session-store/module": {
68
+ "types": "./session-store/src/module.d.ts",
69
+ "default": "./session-store/src/module.js"
70
+ },
71
+ "./session-tokens-store/module": {
72
+ "types": "./session-tokens-store/src/module.d.ts",
73
+ "default": "./session-tokens-store/src/module.js"
74
+ },
75
+ "./subject-revocation-store/module": {
76
+ "types": "./subject-revocation-store/src/module.d.ts",
77
+ "default": "./subject-revocation-store/src/module.js"
78
+ },
79
+ "./tokens-store/module": {
80
+ "types": "./tokens-store/src/module.d.ts",
81
+ "default": "./tokens-store/src/module.js"
82
+ },
83
+ "./users-store/module": {
84
+ "types": "./users-store/src/module.d.ts",
85
+ "default": "./users-store/src/module.js"
86
+ },
87
+ "./webauthn-store/module": {
88
+ "types": "./webauthn-store/src/module.d.ts",
89
+ "default": "./webauthn-store/src/module.js"
90
+ }
91
+ },
92
+ "dependencies": {
93
+ "@o3co/auth-provider-delegation": "0.18.0-rc.1",
94
+ "@o3co/auth-provider-foundation": "0.18.0-rc.1",
95
+ "@o3co/auth-provider-identity": "0.18.0-rc.1",
96
+ "@o3co/auth-provider-oauth": "0.18.0-rc.1",
97
+ "@o3co/auth-provider-passkey": "0.18.0-rc.1",
98
+ "@o3co/auth-provider-second-factor": "0.18.0-rc.1",
99
+ "@o3co/auth-provider-upstream-login": "0.18.0-rc.1",
100
+ "zod": "4.6.5"
9
101
  }
10
- }
102
+ }
@@ -0,0 +1,3 @@
1
+ # refresh-store
2
+
3
+ Wires `refresh`'s store interfaces to `records`: families, what each redemption left and the family of each access token to records, the families of each session and the access tokens of each family to keyed sets on `kernel`'s clock, and the families to settle to deferred work. Each has its own space, which declares a guarantee for each need `refresh` states, so names from different interfaces never meet. The operator section sets `families-per-session` and `tokens-per-family` (1–10000, default 1000), the caps of the keyed sets; each set is one record rewritten whole, so its cap stays small, and 1,000 is more than a client should need within one access token's lifetime. Past a cap, `refresh` revokes what is pushed out. The families to settle are spread over `settle-shards` shards (1–65536, default 1024) of up to `settles-per-shard` families (1–10000, default 1000); a family stays listed only while revoking its tokens keeps failing, so the defaults, about a million, leave room for a long outage while one shard stays near 50 KB. A need with nothing mapped to it fails the type check, and `refresh`'s store contract, run on a store that loses what a missing guarantee allows, checks what each guarantee means. The wiring only maps, with no branches or loops. Depends on `kernel`, `refresh`, `records` and `store`.
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@o3co/auth-provider-foundation/kernel").Module;
2
+ export default _default;
@@ -0,0 +1,60 @@
1
+ import { defineModule } from "@o3co/auth-provider-foundation/kernel";
2
+ import { deferredIn, keyedSetsIn, recordsIn } from "@o3co/auth-provider-foundation/records";
3
+ import { familyStore, issuedAccess, redemptionStore, sessionFamilies, settleList, tokenFamilies, } from "@o3co/auth-provider-oauth/refresh";
4
+ import { spaces, store } from "@o3co/auth-provider-foundation/store";
5
+ import { section } from "./section.js";
6
+ /** Each need refresh states, as the guarantee a space declares for it. */
7
+ const guaranteeFor = {
8
+ neverEvicted: "no-eviction",
9
+ survivesCrash: "durable",
10
+ survivesFailover: "replicated",
11
+ };
12
+ const guarantees = Object.values(guaranteeFor);
13
+ const families = { name: "refresh-store.families", guarantees };
14
+ const redemptions = { name: "refresh-store.redemptions", guarantees };
15
+ const bySession = { name: "refresh-store.session-families", guarantees };
16
+ const byFamily = { name: "refresh-store.issued-access", guarantees };
17
+ const links = { name: "refresh-store.token-families", guarantees };
18
+ const settles = { name: "refresh-store.settles", guarantees };
19
+ /** A space's place: the composition's store, with its log and randomness. */
20
+ const placeIn = async (c, space) => ({
21
+ store: await c.get(store),
22
+ space,
23
+ log: c.log,
24
+ random: c.random,
25
+ });
26
+ export default defineModule({ name: "refresh-store", section }, (m) => [
27
+ m.contribute(spaces).by(() => families),
28
+ m.contribute(spaces).by(() => redemptions),
29
+ m.contribute(spaces).by(() => bySession),
30
+ m.contribute(spaces).by(() => byFamily),
31
+ m.contribute(spaces).by(() => links),
32
+ m.contribute(spaces).by(() => settles),
33
+ m.provide(familyStore).by(async (c) => {
34
+ const records = recordsIn(await placeIn(c, families));
35
+ return { save: records.create, read: records.read, update: records.change };
36
+ }),
37
+ m.provide(redemptionStore).by(async (c) => {
38
+ const records = recordsIn(await placeIn(c, redemptions));
39
+ return { save: records.create, read: records.read };
40
+ }),
41
+ m.provide(tokenFamilies).by(async (c) => {
42
+ const records = recordsIn(await placeIn(c, links));
43
+ return { save: records.create, read: records.read };
44
+ }),
45
+ m.provide(sessionFamilies).by(async (c) => keyedSetsIn({
46
+ ...(await placeIn(c, bySession)),
47
+ cap: c.section["families-per-session"],
48
+ clock: c.clock,
49
+ })),
50
+ m.provide(issuedAccess).by(async (c) => keyedSetsIn({
51
+ ...(await placeIn(c, byFamily)),
52
+ cap: c.section["tokens-per-family"],
53
+ clock: c.clock,
54
+ })),
55
+ m.provide(settleList).by(async (c) => deferredIn({
56
+ ...(await placeIn(c, settles)),
57
+ shards: c.section["settle-shards"],
58
+ perShard: c.section["settles-per-shard"],
59
+ })),
60
+ ]);
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+ /** How many members each list keeps to a key, and how the settle list is spread; the card says why the defaults. */
3
+ export declare const section: z.ZodObject<{
4
+ "families-per-session": z.ZodDefault<z.ZodNumber>;
5
+ "tokens-per-family": z.ZodDefault<z.ZodNumber>;
6
+ "settle-shards": z.ZodDefault<z.ZodNumber>;
7
+ "settles-per-shard": z.ZodDefault<z.ZodNumber>;
8
+ }, z.core.$strict>;
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ /** How many members each list keeps to a key, and how the settle list is spread; the card says why the defaults. */
3
+ export const section = z.strictObject({
4
+ "families-per-session": z
5
+ .number()
6
+ .int()
7
+ .min(1)
8
+ .max(10_000)
9
+ .default(1000)
10
+ .describe("How many refresh token families a session's set keeps; past it, one is pushed out and revoked."),
11
+ "tokens-per-family": z
12
+ .number()
13
+ .int()
14
+ .min(1)
15
+ .max(10_000)
16
+ .default(1000)
17
+ .describe("How many access tokens a family's set keeps; past it, one is pushed out and revoked."),
18
+ "settle-shards": z
19
+ .number()
20
+ .int()
21
+ .min(1)
22
+ .max(65_536)
23
+ .default(1024)
24
+ .describe("How many shards the list of families to settle is spread over."),
25
+ "settles-per-shard": z
26
+ .number()
27
+ .int()
28
+ .min(1)
29
+ .max(10_000)
30
+ .default(1000)
31
+ .describe("How many families to settle one shard holds at most."),
32
+ });
@@ -0,0 +1,3 @@
1
+ # rp-logout-store
2
+
3
+ Wires `rp-logout`'s store interfaces to `records`: the clients of each session to keyed sets on `kernel`'s clock, and the notices not yet delivered to deferred work. Each has its own space, which declares a guarantee for each need `rp-logout` states. The operator section sets `clients-per-session` (1–1000, default 64), the cap of each session's set; a session's clients are those that redeemed a code in it, few in practice, and one pushed out over the cap is answered, so `rp-logout` logs it. The notices are spread over `notice-shards` shards (1–65536, default 64) of up to `notices-per-shard` notices (1–10000, default 1000), and an add to a full shard is refused rather than push one out; a notice stays only while its client cannot be reached, so the defaults, about 64,000, leave room for an outage of some clients. A need with nothing mapped to it fails the type check, and `rp-logout`'s store contract, run on a store that loses what a missing guarantee allows, checks what each guarantee means. The wiring only maps, with no branches or loops. Depends on `kernel`, `rp-logout`, `records` and `store`.
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@o3co/auth-provider-foundation/kernel").Module;
2
+ export default _default;
@@ -0,0 +1,39 @@
1
+ import { defineModule } from "@o3co/auth-provider-foundation/kernel";
2
+ import { deferredIn, keyedSetsIn } from "@o3co/auth-provider-foundation/records";
3
+ import { pendingNotices, sessionClients, } from "@o3co/auth-provider-oauth/rp-logout";
4
+ import { spaces, store } from "@o3co/auth-provider-foundation/store";
5
+ import { section } from "./section.js";
6
+ /** Each need rp-logout states, as the guarantee a space declares for it. */
7
+ const guaranteeFor = {
8
+ neverEvicted: "no-eviction",
9
+ survivesCrash: "durable",
10
+ survivesFailover: "replicated",
11
+ };
12
+ const held = { name: "rp-logout-store.clients", guarantees: Object.values(guaranteeFor) };
13
+ /** The notices state the same needs; typed by their own, so a need they add alone fails the type check. */
14
+ const noticeGuaranteeFor = guaranteeFor;
15
+ const pending = {
16
+ name: "rp-logout-store.notices",
17
+ guarantees: Object.values(noticeGuaranteeFor),
18
+ };
19
+ /** A space's place: the composition's store, with its log and randomness. */
20
+ const placeIn = async (c, space) => ({
21
+ store: await c.get(store),
22
+ space,
23
+ log: c.log,
24
+ random: c.random,
25
+ });
26
+ export default defineModule({ name: "rp-logout-store", section }, (m) => [
27
+ m.contribute(spaces).by(() => held),
28
+ m.contribute(spaces).by(() => pending),
29
+ m.provide(sessionClients).by(async (c) => keyedSetsIn({
30
+ ...(await placeIn(c, held)),
31
+ cap: c.section["clients-per-session"],
32
+ clock: c.clock,
33
+ })),
34
+ m.provide(pendingNotices).by(async (c) => deferredIn({
35
+ ...(await placeIn(c, pending)),
36
+ shards: c.section["notice-shards"],
37
+ perShard: c.section["notices-per-shard"],
38
+ })),
39
+ ]);
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ /** How many clients the set keeps to a session, and how the pending notices are spread; the card says why the defaults. */
3
+ export declare const section: z.ZodObject<{
4
+ "clients-per-session": z.ZodDefault<z.ZodNumber>;
5
+ "notice-shards": z.ZodDefault<z.ZodNumber>;
6
+ "notices-per-shard": z.ZodDefault<z.ZodNumber>;
7
+ }, z.core.$strict>;
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ /** How many clients the set keeps to a session, and how the pending notices are spread; the card says why the defaults. */
3
+ export const section = z.strictObject({
4
+ "clients-per-session": z
5
+ .number()
6
+ .int()
7
+ .min(1)
8
+ .max(1000)
9
+ .default(64)
10
+ .describe("How many clients a session's set keeps; past it, one is pushed out and logged."),
11
+ "notice-shards": z
12
+ .number()
13
+ .int()
14
+ .min(1)
15
+ .max(65_536)
16
+ .default(64)
17
+ .describe("How many shards the logout notices not yet delivered are spread over."),
18
+ "notices-per-shard": z
19
+ .number()
20
+ .int()
21
+ .min(1)
22
+ .max(10_000)
23
+ .default(1000)
24
+ .describe("How many undelivered notices one shard holds; an add to a full shard is refused."),
25
+ });
@@ -0,0 +1,3 @@
1
+ # session-store
2
+
3
+ Wires `session-lifecycle`'s store interfaces to `records`: session records to records, the cookie index to records under a secret, so a cookie's secret never reaches the store, and the list of closings to deferred work. Each has its own space, so a handle and a cookie's name never meet, and every space but the listings confirms its reads, as `session-lifecycle` needs: an entry decides on a raise or a close another request wrote, so it reads only what a failover keeps. The list of closings is spread over `closing-shards` shards (1–65536, default 1024) of up to `closings-per-shard` sessions (1–10000, default 1000); a session stays listed only while a participant keeps failing to close, so the defaults, about a million, leave room for a long outage while one shard stays near 50 KB. Each subject's listed sessions are keyed sets on `kernel`'s clock, of up to `sessions-per-subject` sessions (1–10000, default 100); a login rewrites its subject's set whole, so the default keeps it near 7 KB, far above what one person holds. Over the cap, the set pushes out the session ending first; `session-lifecycle` logs it and closes it, listing the closing first so a crash still finishes it. A need with nothing mapped to it, a guarantee or records under a secret, fails the type check, and `session-lifecycle`'s store contract, run on a store that loses what a missing guarantee allows, checks what each guarantee means. The wiring only maps, with no branches or loops. Depends on `kernel`, `session-lifecycle`, `records` and `store`.
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@o3co/auth-provider-foundation/kernel").Module;
2
+ export default _default;
@@ -0,0 +1,65 @@
1
+ import { defineModule } from "@o3co/auth-provider-foundation/kernel";
2
+ import { deferredIn, keyedSetsIn, recordsIn, secretRecordsIn } from "@o3co/auth-provider-foundation/records";
3
+ import { closingList, cookieIndex, sessionStore, subjectSessions, } from "@o3co/auth-provider-identity/session-lifecycle";
4
+ import { spaces, store } from "@o3co/auth-provider-foundation/store";
5
+ import { section } from "./section.js";
6
+ /** Each need session-lifecycle states, as the guarantee a space declares for it. */
7
+ const guaranteeFor = {
8
+ neverEvicted: "no-eviction",
9
+ survivesCrash: "durable",
10
+ survivesFailover: "replicated",
11
+ readsConfirmed: "confirmed-reads",
12
+ };
13
+ const guarantees = Object.values(guaranteeFor);
14
+ /** Each need the cookie index states, as what meets it: a guarantee its space declares, or records under a secret. */
15
+ const { namesFromSecret: cookieRecordsFor, ...cookieGuaranteeFor } = {
16
+ ...guaranteeFor,
17
+ namesFromSecret: secretRecordsIn,
18
+ };
19
+ const sessions = { name: "session-store.sessions", guarantees };
20
+ const cookies = {
21
+ name: "session-store.cookies",
22
+ guarantees: Object.values(cookieGuaranteeFor),
23
+ };
24
+ const closings = { name: "session-store.closings", guarantees };
25
+ const { neverEvicted, survivesCrash, survivesFailover } = guaranteeFor;
26
+ const listedGuaranteeFor = {
27
+ neverEvicted,
28
+ survivesCrash,
29
+ survivesFailover,
30
+ };
31
+ const subjects = {
32
+ name: "session-store.subjects",
33
+ guarantees: Object.values(listedGuaranteeFor),
34
+ };
35
+ /** A space's place: the composition's store, with its log and randomness. */
36
+ const placeIn = async (c, space) => ({
37
+ store: await c.get(store),
38
+ space,
39
+ log: c.log,
40
+ random: c.random,
41
+ });
42
+ export default defineModule({ name: "session-store", section }, (m) => [
43
+ m.contribute(spaces).by(() => sessions),
44
+ m.contribute(spaces).by(() => cookies),
45
+ m.contribute(spaces).by(() => closings),
46
+ m.contribute(spaces).by(() => subjects),
47
+ m.provide(sessionStore).by(async (c) => {
48
+ const records = recordsIn(await placeIn(c, sessions));
49
+ return { save: records.create, read: records.read, update: records.change };
50
+ }),
51
+ m.provide(cookieIndex).by(async (c) => {
52
+ const records = cookieRecordsFor(await placeIn(c, cookies));
53
+ return { save: records.create, read: records.read, remove: records.remove };
54
+ }),
55
+ m.provide(subjectSessions).by(async (c) => keyedSetsIn({
56
+ ...(await placeIn(c, subjects)),
57
+ cap: c.section["sessions-per-subject"],
58
+ clock: c.clock,
59
+ })),
60
+ m.provide(closingList).by(async (c) => deferredIn({
61
+ ...(await placeIn(c, closings)),
62
+ shards: c.section["closing-shards"],
63
+ perShard: c.section["closings-per-shard"],
64
+ })),
65
+ ]);
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ /** How the list of closings is spread, and how many sessions a subject's listing keeps; the card says why the defaults. */
3
+ export declare const section: z.ZodObject<{
4
+ "closing-shards": z.ZodDefault<z.ZodNumber>;
5
+ "closings-per-shard": z.ZodDefault<z.ZodNumber>;
6
+ "sessions-per-subject": z.ZodDefault<z.ZodNumber>;
7
+ }, z.core.$strict>;
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ /** How the list of closings is spread, and how many sessions a subject's listing keeps; the card says why the defaults. */
3
+ export const section = z.strictObject({
4
+ "closing-shards": z
5
+ .number()
6
+ .int()
7
+ .min(1)
8
+ .max(65_536)
9
+ .default(1024)
10
+ .describe("How many shards the list of sessions still closing is spread over."),
11
+ "closings-per-shard": z
12
+ .number()
13
+ .int()
14
+ .min(1)
15
+ .max(10_000)
16
+ .default(1000)
17
+ .describe("How many sessions still closing one shard holds at most."),
18
+ "sessions-per-subject": z
19
+ .number()
20
+ .int()
21
+ .min(1)
22
+ .max(10_000)
23
+ .default(100)
24
+ .describe("How many sessions a subject's listing keeps; past it, the one ending first is pushed out and logged."),
25
+ });
@@ -0,0 +1,3 @@
1
+ # session-tokens-store
2
+
3
+ Wires `session-tokens`' store interfaces to `records`: the tokens issued in each session to keyed sets on `kernel`'s clock, the token index to records, and the sessions pending a push-out to deferred work. Each has its own space, which declares a guarantee for each need `session-tokens` states. The operator section sets `references-per-session` (1–10000, default 1000), the cap of each session's set: past it, the set answers the reference that ends first as pushed out, keeping it awaiting in the same write, and `session-tokens` revokes its token. The index keeps one record per token id with no cap, ended by the store after its lifetime, and names it by the token id as it is, as `session-tokens` states no names from secrets. The pending sessions are spread over `pending-shards` shards (1–65536, default 64) of up to `pending-per-shard` sessions (1–10000, default 1000), and refuse when a shard is full rather than push one out; a session is listed when an add comes near its cap, and leaves once what it pushed out is revoked, so the defaults, about 64,000, leave room for an outage of revocation. A need with nothing mapped to it fails the type check, and `session-tokens`' store contract, run on a store that loses what a missing guarantee allows, checks what each guarantee means. The wiring only maps, with no branches or loops. Depends on `kernel`, `session-tokens`, `records` and `store`.
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@o3co/auth-provider-foundation/kernel").Module;
2
+ export default _default;
@@ -0,0 +1,55 @@
1
+ import { defineModule } from "@o3co/auth-provider-foundation/kernel";
2
+ import { deferredIn, keyedSetsIn, recordsIn } from "@o3co/auth-provider-foundation/records";
3
+ import { issuedTokens, pendingSessions, tokenIndex, } from "@o3co/auth-provider-oauth/session-tokens";
4
+ import { spaces, store } from "@o3co/auth-provider-foundation/store";
5
+ import { section } from "./section.js";
6
+ /** Each need session-tokens states, as the guarantee a space declares for it. */
7
+ const guaranteeFor = {
8
+ neverEvicted: "no-eviction",
9
+ survivesCrash: "durable",
10
+ survivesFailover: "replicated",
11
+ };
12
+ const issued = {
13
+ name: "session-tokens-store.issued",
14
+ guarantees: Object.values(guaranteeFor),
15
+ };
16
+ const indexGuaranteeFor = guaranteeFor;
17
+ const indexed = {
18
+ name: "session-tokens-store.index",
19
+ guarantees: Object.values(indexGuaranteeFor),
20
+ };
21
+ const pendingGuaranteeFor = guaranteeFor;
22
+ const pending = {
23
+ name: "session-tokens-store.pending-sessions",
24
+ guarantees: Object.values(pendingGuaranteeFor),
25
+ };
26
+ /** A space's place: the composition's store, with its log and randomness. */
27
+ const placeIn = async (c, space) => ({
28
+ store: await c.get(store),
29
+ space,
30
+ log: c.log,
31
+ random: c.random,
32
+ });
33
+ export default defineModule({ name: "session-tokens-store", section }, (m) => [
34
+ m.contribute(spaces).by(() => issued),
35
+ m.contribute(spaces).by(() => indexed),
36
+ m.contribute(spaces).by(() => pending),
37
+ m.provide(issuedTokens).by(async (c) => {
38
+ const cap = c.section["references-per-session"];
39
+ const sets = keyedSetsIn({
40
+ ...(await placeIn(c, issued)),
41
+ cap,
42
+ clock: c.clock,
43
+ });
44
+ return { ...sets, size: cap };
45
+ }),
46
+ m.provide(tokenIndex).by(async (c) => {
47
+ const records = recordsIn(await placeIn(c, indexed));
48
+ return { save: records.create, read: records.read };
49
+ }),
50
+ m.provide(pendingSessions).by(async (c) => deferredIn({
51
+ ...(await placeIn(c, pending)),
52
+ shards: c.section["pending-shards"],
53
+ perShard: c.section["pending-per-shard"],
54
+ })),
55
+ ]);
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ /** How many references the set keeps to a session, and how the pending sessions are spread; the card says why the defaults. */
3
+ export declare const section: z.ZodObject<{
4
+ "references-per-session": z.ZodDefault<z.ZodNumber>;
5
+ "pending-shards": z.ZodDefault<z.ZodNumber>;
6
+ "pending-per-shard": z.ZodDefault<z.ZodNumber>;
7
+ }, z.core.$strict>;
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ /** How many references the set keeps to a session, and how the pending sessions are spread; the card says why the defaults. */
3
+ export const section = z.strictObject({
4
+ "references-per-session": z
5
+ .number()
6
+ .int()
7
+ .min(1)
8
+ .max(10_000)
9
+ .default(1000)
10
+ .describe("How many token references a session's set keeps; past it, one is pushed out and its token revoked."),
11
+ "pending-shards": z
12
+ .number()
13
+ .int()
14
+ .min(1)
15
+ .max(65_536)
16
+ .default(64)
17
+ .describe("How many shards the sessions pending a push-out are spread over."),
18
+ "pending-per-shard": z
19
+ .number()
20
+ .int()
21
+ .min(1)
22
+ .max(10_000)
23
+ .default(1000)
24
+ .describe("How many pending sessions one shard holds; an add to a full shard is refused."),
25
+ });
@@ -0,0 +1,3 @@
1
+ # subject-revocation-store
2
+
3
+ Wires `subject-revocation`'s store interface, boundaries by subject, to `records`' records, kept without end. Its one space declares a guarantee for each need `subject-revocation` states. A need with nothing mapped to it fails the type check, and `subject-revocation`'s store contract, run on a store that loses what a missing guarantee allows, checks what each guarantee means. The wiring only maps, with no branches or loops. Depends on `kernel`, `subject-revocation`, `records` and `store`.
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@o3co/auth-provider-foundation/kernel").Module;
2
+ export default _default;