@cosmicdrift/kumiko-bundled-features 0.116.1 → 0.118.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-bundled-features",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.118.0",
|
|
4
4
|
"description": "Built-in features — tenant, user, auth, delivery. The stuff you'd rewrite anyway, already typed.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -95,11 +95,11 @@
|
|
|
95
95
|
"./step-dispatcher": "./src/step-dispatcher/index.ts"
|
|
96
96
|
},
|
|
97
97
|
"dependencies": {
|
|
98
|
-
"@cosmicdrift/kumiko-dispatcher-live": "0.
|
|
99
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
100
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
101
|
-
"@cosmicdrift/kumiko-renderer": "0.
|
|
102
|
-
"@cosmicdrift/kumiko-renderer-web": "0.
|
|
98
|
+
"@cosmicdrift/kumiko-dispatcher-live": "0.118.0",
|
|
99
|
+
"@cosmicdrift/kumiko-framework": "0.118.0",
|
|
100
|
+
"@cosmicdrift/kumiko-headless": "0.118.0",
|
|
101
|
+
"@cosmicdrift/kumiko-renderer": "0.118.0",
|
|
102
|
+
"@cosmicdrift/kumiko-renderer-web": "0.118.0",
|
|
103
103
|
"@mollie/api-client": "^4.5.0",
|
|
104
104
|
"@node-rs/argon2": "^2.0.2",
|
|
105
105
|
"@types/nodemailer": "^8.0.0",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { createPersonalAccessTokensFeature } from "../feature";
|
|
3
|
+
|
|
4
|
+
describe("createPersonalAccessTokensFeature toggleable-option (tier-gating)", () => {
|
|
5
|
+
test("without toggleable: feature is always-on (toggleableDefault undefined)", () => {
|
|
6
|
+
expect(createPersonalAccessTokensFeature({ scopes: {} }).toggleableDefault).toBeUndefined();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
test("toggleable:{default:false} makes the feature tier-gatable, fail-closed", () => {
|
|
10
|
+
const feature = createPersonalAccessTokensFeature({
|
|
11
|
+
scopes: {},
|
|
12
|
+
toggleable: { default: false },
|
|
13
|
+
});
|
|
14
|
+
expect(feature.toggleableDefault).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("toggleable:{default:true} declares toggleable, enabled-by-default", () => {
|
|
18
|
+
const feature = createPersonalAccessTokensFeature({
|
|
19
|
+
scopes: {},
|
|
20
|
+
toggleable: { default: true },
|
|
21
|
+
});
|
|
22
|
+
expect(feature.toggleableDefault).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -17,6 +17,10 @@ export type PersonalAccessTokensOptions = {
|
|
|
17
17
|
// Per-token request rate limit for PAT-authenticated calls. Defaults to
|
|
18
18
|
// PAT_DEFAULT_RATE_LIMIT (120/60s). run-prod-app builds the limiter from this.
|
|
19
19
|
readonly rateLimit?: PatRateLimit;
|
|
20
|
+
/** Make the whole feature tier-gatable via the tier-engine. Use
|
|
21
|
+
* { default: false } for fail-closed gating (feature off until a tier grants
|
|
22
|
+
* it). Omit to keep PAT always-on (default). */
|
|
23
|
+
readonly toggleable?: { readonly default: boolean };
|
|
20
24
|
};
|
|
21
25
|
|
|
22
26
|
export type PatFeatureExports = {
|
|
@@ -35,9 +39,13 @@ export function createPersonalAccessTokensFeature(
|
|
|
35
39
|
const { scopes } = options;
|
|
36
40
|
return defineFeature(PAT_FEATURE, (r) => {
|
|
37
41
|
r.describe(
|
|
38
|
-
"Long-lived, revocable Personal Access Tokens for headless HTTP-API access. Stores SHA-256 token hashes in the `read_api_tokens` direct-write table; the plaintext is returned once at creation. `create`/`revoke`/`mine` manage a user's own tokens and `available-scopes` lists the app-declared scope catalog. Bearer tokens carrying the PAT prefix are resolved before jwt.verify (roles resolved live, granted scopes enforced fail-closed at the API boundary) — the resolver is wired via run-prod-app, not the dispatcher.",
|
|
42
|
+
"Long-lived, revocable Personal Access Tokens for headless HTTP-API access. Stores SHA-256 token hashes in the `read_api_tokens` direct-write table; the plaintext is returned once at creation. `create`/`revoke`/`mine` manage a user's own tokens and `available-scopes` lists the app-declared scope catalog. Bearer tokens carrying the PAT prefix are resolved before jwt.verify (roles resolved live, granted scopes enforced fail-closed at the API boundary) — the resolver is wired via run-prod-app, not the dispatcher. Pass { toggleable: { default: false } } to tier-gate the whole feature.",
|
|
39
43
|
);
|
|
40
44
|
r.uiHints({ displayLabel: "Personal Access Tokens", category: "identity", recommended: false });
|
|
45
|
+
// Opt-in tier-gating (mirrors ledger/tags): when set, the feature declares
|
|
46
|
+
// itself r.toggleable so the dispatcher gate + tier-engine can switch PAT
|
|
47
|
+
// on/off per tenant. { default: false } = fail-closed until a tier grants it.
|
|
48
|
+
if (options.toggleable !== undefined) r.toggleable(options.toggleable);
|
|
41
49
|
// Resolver reads memberships + users on every PAT request to build live
|
|
42
50
|
// roles — make both boot-time deps so a mis-wiring fails validateBoot.
|
|
43
51
|
r.requires("user", "tenant");
|