@inixiative/signet 0.12.0 → 0.12.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.
- package/README.md +1 -1
- package/package.json +2 -2
- package/src/archive.ts +45 -3
- package/src/client.ts +3 -1
- package/src/contracts.ts +3 -1
- package/src/lens.ts +13 -0
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ This package is the one implementation of that protocol, shared by Kingdom (whic
|
|
|
16
16
|
- a **person or their agent** acts as themselves with a Kingdom API token plus a proof from its key: `requestSignet` asks for a Signet on an integration (a `signetRequest` Inquiry, approved at once when the caller manages the integration), `awaitSignet` polls `collectSignet` until it is approved, and `enrollSignet` enrolls the key on a Signet an owner granted directly (`owner/grant`). `saveCollectedSignet` writes either result next to the key;
|
|
17
17
|
- `installation`: the layout every installation shares, under one root per product (a Foundry's `kingdom/`, `~/.kcp`): one directory per Kingdom host with its key and one file per Signet (`installationPaths`, `installationDirectory`, `signetCredentialFile`, `heldCredentials`), `privateDirectory`, and `defaultInstallationName(product)`. `listedSignets`, `heldSignetFile` and `withdrawRegistration` read and act on it. `holdPersonSignets` enrolls the key on Signets issued to a person, under the same per-directory `withHoldLock` as `holdInstallationSignets`, so a person login and an installation sync never enroll over each other;
|
|
18
18
|
- `SignetHolders`, a cache of each held Signet's `access/describe` (with its `holder`), keyed by credential file or by the caller's own `keyOf`, refreshed after `stale()`;
|
|
19
|
-
- `SignetClient`, which renews its access token and signs each call: `describe`, `execute`, task settlement, and the run actions a Foundry uses for inference (`resolveRun`, `delegateRun`, `renewRun`, `revokeRun`), and for a subscription run `releaseSubscription` and `
|
|
19
|
+
- `SignetClient`, which renews its access token and signs each call: `describe`, `execute`, task settlement, and the run actions a Foundry uses for inference (`resolveRun`, `delegateRun`, `renewRun`, `revokeRun`), and for a subscription run `releaseSubscription`, `reportSubscriptionLimits` and `reportCredentialRejected` (the provider rejected the login a release handed out).
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
22
|
import { holdInstallationSignets, InstallationSocket, pairInstallation, SignetClient } from '@inixiative/signet';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inixiative/signet",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2",
|
|
4
4
|
"description": "Present Kingdom Signets: the wire contracts, DPoP proofs, device pairing and a renewing client shared by Kingdom, Archive, Foundry and Oracle.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@asteasolutions/zod-to-openapi": "^9.1.0",
|
|
37
37
|
"@biomejs/biome": "2.5.2",
|
|
38
|
-
"@inixiative/config": "^0.5.
|
|
38
|
+
"@inixiative/config": "^0.5.178",
|
|
39
39
|
"@inixiative/json-rules": "^3.16.0",
|
|
40
40
|
"@types/bun": "1.4.4",
|
|
41
41
|
"lefthook": "2.1.9",
|
package/src/archive.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { Condition } from '@inixiative/json-rules';
|
|
1
2
|
import { z } from 'zod';
|
|
2
|
-
import { type GrantLens, projectionFilters, projectionShows } from './lens';
|
|
3
|
+
import { type GrantLens, type LensLayer, projectionFilters, projectionShows } from './lens';
|
|
3
4
|
import { type OperationScope, scopeRefusal } from './operations';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -12,7 +13,14 @@ export const archiveLibraryResourceKind = 'archiveLibrary';
|
|
|
12
13
|
|
|
13
14
|
/** An Archive session id: `archiveKey(snapshot)`, the digest of its source and session. */
|
|
14
15
|
export const archiveDocumentIdSchema = z.string().regex(/^[a-f0-9]{64}$/);
|
|
15
|
-
export const archiveFieldSchema = z.enum([
|
|
16
|
+
export const archiveFieldSchema = z.enum([
|
|
17
|
+
'id',
|
|
18
|
+
'title',
|
|
19
|
+
'content',
|
|
20
|
+
'tags',
|
|
21
|
+
'projectId',
|
|
22
|
+
'createdAt',
|
|
23
|
+
]);
|
|
16
24
|
export type ArchiveField = z.infer<typeof archiveFieldSchema>;
|
|
17
25
|
|
|
18
26
|
/** The operations an `archiveLibrary` resource carries. */
|
|
@@ -42,7 +50,7 @@ export const archiveSourceOperations = [
|
|
|
42
50
|
export const isArchiveSourceOperation = (operation: ArchiveOperation) =>
|
|
43
51
|
(archiveSourceOperations as readonly ArchiveOperation[]).includes(operation);
|
|
44
52
|
|
|
45
|
-
const fieldsSchema = z.array(archiveFieldSchema).min(1).max(
|
|
53
|
+
const fieldsSchema = z.array(archiveFieldSchema).min(1).max(archiveFieldSchema.options.length);
|
|
46
54
|
|
|
47
55
|
/**
|
|
48
56
|
* The input each Archive operation takes. `access/execute` carries the same fields beside
|
|
@@ -90,6 +98,40 @@ export const archiveLensRefusal = (operation: ArchiveOperation, lens: GrantLens)
|
|
|
90
98
|
return null;
|
|
91
99
|
};
|
|
92
100
|
|
|
101
|
+
type ArchiveInput<O extends ArchiveOperation> = z.infer<(typeof archiveInputSchemas)[O]>;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* What one call filters on, as a json-rules condition over the Archive document, or undefined when
|
|
105
|
+
* it filters on nothing. Kingdom gates it with `validateRuleInLens` against the grant's composed
|
|
106
|
+
* lens: a filter on a field the lens hides (`projectId`, a `tag`) would say which documents carry a
|
|
107
|
+
* value the holder can't see, and is refused with the lens's own code.
|
|
108
|
+
*/
|
|
109
|
+
export const archiveCallCondition = <O extends ArchiveOperation>(
|
|
110
|
+
_operation: O,
|
|
111
|
+
input: ArchiveInput<O>,
|
|
112
|
+
): Condition | undefined => {
|
|
113
|
+
const rules: Condition[] = [
|
|
114
|
+
...('projectId' in input && input.projectId !== undefined
|
|
115
|
+
? [{ field: 'projectId', operator: 'equals' as const, value: input.projectId }]
|
|
116
|
+
: []),
|
|
117
|
+
...('tag' in input && input.tag !== undefined
|
|
118
|
+
? [{ field: 'tags', operator: 'contains' as const, value: input.tag }]
|
|
119
|
+
: []),
|
|
120
|
+
];
|
|
121
|
+
return rules.length === 0 ? undefined : rules.length === 1 ? rules[0] : { all: rules };
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The fields one call asks for, as a lens layer that picks them, or undefined when it asks for none.
|
|
126
|
+
* Kingdom validates it under the grant's composed lens (`validateNarrowing`): a field the lens hides
|
|
127
|
+
* is refused there.
|
|
128
|
+
*/
|
|
129
|
+
export const archiveCallNarrowing = <O extends ArchiveOperation>(
|
|
130
|
+
_operation: O,
|
|
131
|
+
input: ArchiveInput<O>,
|
|
132
|
+
): LensLayer | undefined =>
|
|
133
|
+
'fields' in input && input.fields?.length ? { root: { picks: [...input.fields] } } : undefined;
|
|
134
|
+
|
|
93
135
|
/** `archiveLensRefusal` over every operation a grant row reaches, `full` meaning all of them. */
|
|
94
136
|
export const archiveGrantRefusal = (scope: OperationScope, lens: GrantLens) =>
|
|
95
137
|
scopeRefusal(scope, archiveOperationSchema.options, (operation) =>
|
package/src/client.ts
CHANGED
|
@@ -500,7 +500,8 @@ export type SignetAction =
|
|
|
500
500
|
| 'renewRun'
|
|
501
501
|
| 'revokeRun'
|
|
502
502
|
| 'releaseSubscription'
|
|
503
|
-
| 'reportSubscriptionLimits'
|
|
503
|
+
| 'reportSubscriptionLimits'
|
|
504
|
+
| 'reportCredentialRejected';
|
|
504
505
|
const signetActions: SignetAction[] = [
|
|
505
506
|
'describe',
|
|
506
507
|
'execute',
|
|
@@ -513,6 +514,7 @@ const signetActions: SignetAction[] = [
|
|
|
513
514
|
'revokeRun',
|
|
514
515
|
'releaseSubscription',
|
|
515
516
|
'reportSubscriptionLimits',
|
|
517
|
+
'reportCredentialRejected',
|
|
516
518
|
];
|
|
517
519
|
|
|
518
520
|
/** Presents one enrolled Signet: renews its access token and signs each call with the device key. */
|
package/src/contracts.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
signetGrantSchema,
|
|
15
15
|
signetResourceSchema,
|
|
16
16
|
} from './grants';
|
|
17
|
-
import { storedLensLayersSchema } from './lens';
|
|
17
|
+
import { storedBaseLensSchema, storedLensLayersSchema } from './lens';
|
|
18
18
|
import {
|
|
19
19
|
foundryIdSchema,
|
|
20
20
|
threadFloorActionSchema,
|
|
@@ -280,6 +280,8 @@ export const hostedSignetSchema = z.object({
|
|
|
280
280
|
id: z.uuid(),
|
|
281
281
|
displayName: z.string(),
|
|
282
282
|
}),
|
|
283
|
+
/** Each base lens the rows' `lens` layers compose under, keyed by `baseLensId(provider, kind)`. */
|
|
284
|
+
baseLenses: z.record(z.string(), storedBaseLensSchema),
|
|
283
285
|
resources: grantsSchema,
|
|
284
286
|
});
|
|
285
287
|
export type InstallationSignet = z.infer<typeof installationSignetSchema>;
|
package/src/lens.ts
CHANGED
|
@@ -34,6 +34,19 @@ export const storedLensLayerSchema = z.strictObject({
|
|
|
34
34
|
});
|
|
35
35
|
export const storedLensLayersSchema = z.array(storedLensLayerSchema).max(20);
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* A base lens as Kingdom's catalog carries it: the json-rules `Lens` itself (its field maps, map name
|
|
39
|
+
* and model) with an `id` and no parents. Only the envelope is checked here; a holder composes it
|
|
40
|
+
* under a grant's layers with json-rules `composeLens`, which validates what is inside.
|
|
41
|
+
*/
|
|
42
|
+
export const storedBaseLensSchema = z.looseObject({
|
|
43
|
+
id: layerId,
|
|
44
|
+
parents: z.array(layerId).max(0),
|
|
45
|
+
mapName: z.string().min(1),
|
|
46
|
+
model: z.string().min(1),
|
|
47
|
+
maps: z.record(z.string(), z.unknown()),
|
|
48
|
+
});
|
|
49
|
+
|
|
37
50
|
/** The id of an integration's base lens for a resource kind's model, in Kingdom's catalog. */
|
|
38
51
|
export const baseLensId = (provider: string, kind: string) => `${provider}:${kind}`;
|
|
39
52
|
|