@camstack/types 1.2.53 → 1.2.54
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/dist/capabilities/oauth-integration.cap.d.ts +59 -0
- package/dist/index.js +59 -0
- package/dist/index.mjs +59 -0
- package/package.json +1 -1
|
@@ -6,6 +6,65 @@ import { type InferProvider } from './capability-definition.js';
|
|
|
6
6
|
* Each provider returns a static descriptor; the core enumerates them
|
|
7
7
|
* to validate the `integration=` query param and resolve the consent
|
|
8
8
|
* label + the scopes baked into the issued token.
|
|
9
|
+
*
|
|
10
|
+
* ## Declaring one
|
|
11
|
+
*
|
|
12
|
+
* An OAuth client is integration-specific knowledge — who the client is, what
|
|
13
|
+
* it may ask for, where it may be sent — so it is declared by the ADDON that
|
|
14
|
+
* owns the integration, never by the kernel and never as a branch inside
|
|
15
|
+
* `oauth2-routes.ts` ([D101](../../../../docs/decisions/adr-0101.md)). Three
|
|
16
|
+
* steps, no others:
|
|
17
|
+
*
|
|
18
|
+
* 1. Add `{ "name": "oauth-integration" }` to the addon's `camstack.addons[]`
|
|
19
|
+
* manifest entry. This is also what tells the hub, at addon-LOAD time, that
|
|
20
|
+
* a descriptor is owed — see "the boot window" below.
|
|
21
|
+
* 2. Return a provider from `onInitialize()`:
|
|
22
|
+
*
|
|
23
|
+
* ```ts
|
|
24
|
+
* const provider: IOauthIntegrationProvider = {
|
|
25
|
+
* getDescriptor: async () => ({
|
|
26
|
+
* integrationId: 'my-thing', // the `integration=` query param
|
|
27
|
+
* displayName: 'My Thing',
|
|
28
|
+
* requestedScopes: [ … ], // see below
|
|
29
|
+
* allowedRedirectPrefixes: ['https://callback.example/'],
|
|
30
|
+
* }),
|
|
31
|
+
* }
|
|
32
|
+
* return [{ capability: oauthIntegrationCapability, provider }]
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* The descriptor must be **static** — it is read on the authorize path, so
|
|
36
|
+
* never put an await on network or disk behind it, and never register it
|
|
37
|
+
* behind one either (a provider is registered only once `onInitialize`
|
|
38
|
+
* RETURNS, so anything awaited before the return delays linking).
|
|
39
|
+
* 3. Nothing else. There is no allow-list to join, no id to register with the
|
|
40
|
+
* core, and no per-integration branch anywhere: `/api/oauth2/authorize` and
|
|
41
|
+
* `/api/oauth2/integrations` are built from this collection alone.
|
|
42
|
+
*
|
|
43
|
+
* **Scopes.** `requestedScopes` is baked into every token this integration is
|
|
44
|
+
* ever issued and the operator consents to it once. Derive it from the tRPC
|
|
45
|
+
* paths the client calls **with that token**, against `METHOD_ACCESS_MAP`, and
|
|
46
|
+
* prefer a narrow `capability:` scope to a `category:` one unless the client
|
|
47
|
+
* genuinely needs a whole family. A category scope grants every future member
|
|
48
|
+
* of that category too. `category:system [create]` has been rejected once and
|
|
49
|
+
* should stay rejected: it hands `addons.installPackage` to an integration.
|
|
50
|
+
*
|
|
51
|
+
* What it does NOT cover: calls the ADDON makes over `ctx.api`, which run as
|
|
52
|
+
* the addon and are not scope-checked. Alexa's descriptor is narrower than
|
|
53
|
+
* Home Assistant's for exactly that reason — its Lambda posts directives and
|
|
54
|
+
* the addon does the work, while the Home Assistant component calls tRPC
|
|
55
|
+
* directly with the token. So `requestedScopes` describes the blast radius of
|
|
56
|
+
* the GRANT, not the reach of the integration; do not widen one to describe the
|
|
57
|
+
* other.
|
|
58
|
+
*
|
|
59
|
+
* **The boot window.** An addon registers its provider after its runner forks
|
|
60
|
+
* and initialises, so between hub start and that moment this collection is
|
|
61
|
+
* incomplete and an `integrationId` can be legitimately absent. The core does
|
|
62
|
+
* not wait, poll or cache around this ([D3](../../../../docs/decisions/adr-0003.md)):
|
|
63
|
+
* it compares the manifest declarers against the registered providers and
|
|
64
|
+
* answers `503 temporarily_unavailable` (with `Retry-After` and the pending
|
|
65
|
+
* addon ids) instead of `400 unknown integration`, and reports
|
|
66
|
+
* `complete: false` on `GET /api/oauth2/integrations`. A client should retry
|
|
67
|
+
* while the list is incomplete rather than conclude the hub cannot do OAuth.
|
|
9
68
|
*/
|
|
10
69
|
declare const OauthIntegrationDescriptorSchema: z.ZodObject<{
|
|
11
70
|
integrationId: z.ZodString;
|
package/dist/index.js
CHANGED
|
@@ -13012,6 +13012,65 @@ var ScopedTokenSchema = zod.z.object({
|
|
|
13012
13012
|
* Each provider returns a static descriptor; the core enumerates them
|
|
13013
13013
|
* to validate the `integration=` query param and resolve the consent
|
|
13014
13014
|
* label + the scopes baked into the issued token.
|
|
13015
|
+
*
|
|
13016
|
+
* ## Declaring one
|
|
13017
|
+
*
|
|
13018
|
+
* An OAuth client is integration-specific knowledge — who the client is, what
|
|
13019
|
+
* it may ask for, where it may be sent — so it is declared by the ADDON that
|
|
13020
|
+
* owns the integration, never by the kernel and never as a branch inside
|
|
13021
|
+
* `oauth2-routes.ts` ([D101](../../../../docs/decisions/adr-0101.md)). Three
|
|
13022
|
+
* steps, no others:
|
|
13023
|
+
*
|
|
13024
|
+
* 1. Add `{ "name": "oauth-integration" }` to the addon's `camstack.addons[]`
|
|
13025
|
+
* manifest entry. This is also what tells the hub, at addon-LOAD time, that
|
|
13026
|
+
* a descriptor is owed — see "the boot window" below.
|
|
13027
|
+
* 2. Return a provider from `onInitialize()`:
|
|
13028
|
+
*
|
|
13029
|
+
* ```ts
|
|
13030
|
+
* const provider: IOauthIntegrationProvider = {
|
|
13031
|
+
* getDescriptor: async () => ({
|
|
13032
|
+
* integrationId: 'my-thing', // the `integration=` query param
|
|
13033
|
+
* displayName: 'My Thing',
|
|
13034
|
+
* requestedScopes: [ … ], // see below
|
|
13035
|
+
* allowedRedirectPrefixes: ['https://callback.example/'],
|
|
13036
|
+
* }),
|
|
13037
|
+
* }
|
|
13038
|
+
* return [{ capability: oauthIntegrationCapability, provider }]
|
|
13039
|
+
* ```
|
|
13040
|
+
*
|
|
13041
|
+
* The descriptor must be **static** — it is read on the authorize path, so
|
|
13042
|
+
* never put an await on network or disk behind it, and never register it
|
|
13043
|
+
* behind one either (a provider is registered only once `onInitialize`
|
|
13044
|
+
* RETURNS, so anything awaited before the return delays linking).
|
|
13045
|
+
* 3. Nothing else. There is no allow-list to join, no id to register with the
|
|
13046
|
+
* core, and no per-integration branch anywhere: `/api/oauth2/authorize` and
|
|
13047
|
+
* `/api/oauth2/integrations` are built from this collection alone.
|
|
13048
|
+
*
|
|
13049
|
+
* **Scopes.** `requestedScopes` is baked into every token this integration is
|
|
13050
|
+
* ever issued and the operator consents to it once. Derive it from the tRPC
|
|
13051
|
+
* paths the client calls **with that token**, against `METHOD_ACCESS_MAP`, and
|
|
13052
|
+
* prefer a narrow `capability:` scope to a `category:` one unless the client
|
|
13053
|
+
* genuinely needs a whole family. A category scope grants every future member
|
|
13054
|
+
* of that category too. `category:system [create]` has been rejected once and
|
|
13055
|
+
* should stay rejected: it hands `addons.installPackage` to an integration.
|
|
13056
|
+
*
|
|
13057
|
+
* What it does NOT cover: calls the ADDON makes over `ctx.api`, which run as
|
|
13058
|
+
* the addon and are not scope-checked. Alexa's descriptor is narrower than
|
|
13059
|
+
* Home Assistant's for exactly that reason — its Lambda posts directives and
|
|
13060
|
+
* the addon does the work, while the Home Assistant component calls tRPC
|
|
13061
|
+
* directly with the token. So `requestedScopes` describes the blast radius of
|
|
13062
|
+
* the GRANT, not the reach of the integration; do not widen one to describe the
|
|
13063
|
+
* other.
|
|
13064
|
+
*
|
|
13065
|
+
* **The boot window.** An addon registers its provider after its runner forks
|
|
13066
|
+
* and initialises, so between hub start and that moment this collection is
|
|
13067
|
+
* incomplete and an `integrationId` can be legitimately absent. The core does
|
|
13068
|
+
* not wait, poll or cache around this ([D3](../../../../docs/decisions/adr-0003.md)):
|
|
13069
|
+
* it compares the manifest declarers against the registered providers and
|
|
13070
|
+
* answers `503 temporarily_unavailable` (with `Retry-After` and the pending
|
|
13071
|
+
* addon ids) instead of `400 unknown integration`, and reports
|
|
13072
|
+
* `complete: false` on `GET /api/oauth2/integrations`. A client should retry
|
|
13073
|
+
* while the list is incomplete rather than conclude the hub cannot do OAuth.
|
|
13015
13074
|
*/
|
|
13016
13075
|
var OauthIntegrationDescriptorSchema = zod.z.object({
|
|
13017
13076
|
/** Stable id used as the `integration=` query param, e.g. 'export-alexa'. */
|
package/dist/index.mjs
CHANGED
|
@@ -13011,6 +13011,65 @@ var ScopedTokenSchema = z.object({
|
|
|
13011
13011
|
* Each provider returns a static descriptor; the core enumerates them
|
|
13012
13012
|
* to validate the `integration=` query param and resolve the consent
|
|
13013
13013
|
* label + the scopes baked into the issued token.
|
|
13014
|
+
*
|
|
13015
|
+
* ## Declaring one
|
|
13016
|
+
*
|
|
13017
|
+
* An OAuth client is integration-specific knowledge — who the client is, what
|
|
13018
|
+
* it may ask for, where it may be sent — so it is declared by the ADDON that
|
|
13019
|
+
* owns the integration, never by the kernel and never as a branch inside
|
|
13020
|
+
* `oauth2-routes.ts` ([D101](../../../../docs/decisions/adr-0101.md)). Three
|
|
13021
|
+
* steps, no others:
|
|
13022
|
+
*
|
|
13023
|
+
* 1. Add `{ "name": "oauth-integration" }` to the addon's `camstack.addons[]`
|
|
13024
|
+
* manifest entry. This is also what tells the hub, at addon-LOAD time, that
|
|
13025
|
+
* a descriptor is owed — see "the boot window" below.
|
|
13026
|
+
* 2. Return a provider from `onInitialize()`:
|
|
13027
|
+
*
|
|
13028
|
+
* ```ts
|
|
13029
|
+
* const provider: IOauthIntegrationProvider = {
|
|
13030
|
+
* getDescriptor: async () => ({
|
|
13031
|
+
* integrationId: 'my-thing', // the `integration=` query param
|
|
13032
|
+
* displayName: 'My Thing',
|
|
13033
|
+
* requestedScopes: [ … ], // see below
|
|
13034
|
+
* allowedRedirectPrefixes: ['https://callback.example/'],
|
|
13035
|
+
* }),
|
|
13036
|
+
* }
|
|
13037
|
+
* return [{ capability: oauthIntegrationCapability, provider }]
|
|
13038
|
+
* ```
|
|
13039
|
+
*
|
|
13040
|
+
* The descriptor must be **static** — it is read on the authorize path, so
|
|
13041
|
+
* never put an await on network or disk behind it, and never register it
|
|
13042
|
+
* behind one either (a provider is registered only once `onInitialize`
|
|
13043
|
+
* RETURNS, so anything awaited before the return delays linking).
|
|
13044
|
+
* 3. Nothing else. There is no allow-list to join, no id to register with the
|
|
13045
|
+
* core, and no per-integration branch anywhere: `/api/oauth2/authorize` and
|
|
13046
|
+
* `/api/oauth2/integrations` are built from this collection alone.
|
|
13047
|
+
*
|
|
13048
|
+
* **Scopes.** `requestedScopes` is baked into every token this integration is
|
|
13049
|
+
* ever issued and the operator consents to it once. Derive it from the tRPC
|
|
13050
|
+
* paths the client calls **with that token**, against `METHOD_ACCESS_MAP`, and
|
|
13051
|
+
* prefer a narrow `capability:` scope to a `category:` one unless the client
|
|
13052
|
+
* genuinely needs a whole family. A category scope grants every future member
|
|
13053
|
+
* of that category too. `category:system [create]` has been rejected once and
|
|
13054
|
+
* should stay rejected: it hands `addons.installPackage` to an integration.
|
|
13055
|
+
*
|
|
13056
|
+
* What it does NOT cover: calls the ADDON makes over `ctx.api`, which run as
|
|
13057
|
+
* the addon and are not scope-checked. Alexa's descriptor is narrower than
|
|
13058
|
+
* Home Assistant's for exactly that reason — its Lambda posts directives and
|
|
13059
|
+
* the addon does the work, while the Home Assistant component calls tRPC
|
|
13060
|
+
* directly with the token. So `requestedScopes` describes the blast radius of
|
|
13061
|
+
* the GRANT, not the reach of the integration; do not widen one to describe the
|
|
13062
|
+
* other.
|
|
13063
|
+
*
|
|
13064
|
+
* **The boot window.** An addon registers its provider after its runner forks
|
|
13065
|
+
* and initialises, so between hub start and that moment this collection is
|
|
13066
|
+
* incomplete and an `integrationId` can be legitimately absent. The core does
|
|
13067
|
+
* not wait, poll or cache around this ([D3](../../../../docs/decisions/adr-0003.md)):
|
|
13068
|
+
* it compares the manifest declarers against the registered providers and
|
|
13069
|
+
* answers `503 temporarily_unavailable` (with `Retry-After` and the pending
|
|
13070
|
+
* addon ids) instead of `400 unknown integration`, and reports
|
|
13071
|
+
* `complete: false` on `GET /api/oauth2/integrations`. A client should retry
|
|
13072
|
+
* while the list is incomplete rather than conclude the hub cannot do OAuth.
|
|
13014
13073
|
*/
|
|
13015
13074
|
var OauthIntegrationDescriptorSchema = z.object({
|
|
13016
13075
|
/** Stable id used as the `integration=` query param, e.g. 'export-alexa'. */
|