@deadair/plugin-sdk 0.39.1 → 0.41.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/README.md +95 -0
- package/dist/boundary.json.safe.d.ts +13 -3
- package/dist/boundary.json.safe.d.ts.map +1 -1
- package/dist/capabilities/output.d.ts +168 -0
- package/dist/capabilities/output.d.ts.map +1 -0
- package/dist/define.plugin.d.ts +3 -0
- package/dist/define.plugin.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -2
- package/dist/index.js.map +1 -1
- package/dist/plugin.host.d.ts +109 -0
- package/dist/plugin.host.d.ts.map +1 -1
- package/dist/plugin.manifest.d.ts +16 -1
- package/dist/plugin.manifest.d.ts.map +1 -1
- package/dist/plugin.permissions.d.ts +23 -0
- package/dist/plugin.permissions.d.ts.map +1 -1
- package/dist/testing/fake.plugin.host.d.ts +34 -1
- package/dist/testing/fake.plugin.host.d.ts.map +1 -1
- package/dist/testing/index.js +56 -0
- package/dist/testing/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,6 +27,7 @@ A plugin extends deadair by declaring capabilities:
|
|
|
27
27
|
| `almanac` | say what happened on a date: a month and a day in, entries out |
|
|
28
28
|
| `scrobble` | report what the station played to somebody else's service |
|
|
29
29
|
| `messaging` | talk to people on a chat platform: messages in, messages out |
|
|
30
|
+
| `output` | play the station on a speaker: a mount's URL in, a device plays |
|
|
30
31
|
| `oauth` | hold operator tokens, obtained through the host's redirect |
|
|
31
32
|
|
|
32
33
|
There is no second axis. `capabilities` is the whole declaration, and the host
|
|
@@ -451,6 +452,57 @@ is a heartbeat timer, and a listener that throws is logged rather than allowed t
|
|
|
451
452
|
reach the event loop. The socket is the shape ServerKit's Socket Mode and Gateway
|
|
452
453
|
clients call `SocketLike`, so `connect: url => host.socket(url)` is all either needs.
|
|
453
454
|
|
|
455
|
+
## When your device speaks its own protocol
|
|
456
|
+
|
|
457
|
+
Some devices are neither HTTP nor a WebSocket: a Chromecast is driven over a TLS
|
|
458
|
+
connection to port 8009 carrying its own length-prefixed messages. `host.tls`
|
|
459
|
+
opens one, under the same policy again:
|
|
460
|
+
|
|
461
|
+
```ts
|
|
462
|
+
const conn = await host.tls('tls://192.168.1.20:8009', { verifyCertificate: false });
|
|
463
|
+
conn.onData(bytes => this.reader.push(bytes)); // bytes, not frames: reassemble your own
|
|
464
|
+
conn.onClose(reason => this.reconnectLater(reason));
|
|
465
|
+
conn.send(frame);
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
Requires the `tls` permission. The URL is `tls://host:port` and the port is
|
|
469
|
+
required, since `tls:` has no default. The host is checked against
|
|
470
|
+
`permissions.network` as the `https:` URL on the same host and port, and a
|
|
471
|
+
connect costs one token from that host's rate bucket.
|
|
472
|
+
|
|
473
|
+
`verifyCertificate: false` is for a device on the operator's own network that
|
|
474
|
+
presents a certificate no public root signs. It is honoured only for an address
|
|
475
|
+
that came from your settings (a `{ fromConfig }` entry), because that is the
|
|
476
|
+
operator saying "this device is mine". For a host your manifest names, or one
|
|
477
|
+
reached through `network.open`, it is refused with `forbidden`.
|
|
478
|
+
|
|
479
|
+
Like a socket, the connection outlives the call that opened it: a plugin may hold
|
|
480
|
+
only a limited number at once (more than sockets, since a speaker plugin holds one
|
|
481
|
+
per device), and disposing the plugin closes every one without calling your close
|
|
482
|
+
listeners. `send` after a close does nothing, and a listener that throws is logged.
|
|
483
|
+
|
|
484
|
+
## When you need to find devices on the network
|
|
485
|
+
|
|
486
|
+
A plugin that drives devices on the operator's network can look for them rather
|
|
487
|
+
than asking for every address. `host.discover` runs an mDNS or SSDP query from the
|
|
488
|
+
host, which owns the multicast sockets so no plugin binds those ports itself:
|
|
489
|
+
|
|
490
|
+
```ts
|
|
491
|
+
const casts = await host.discover({ protocol: 'mdns', service: '_googlecast._tcp' });
|
|
492
|
+
// [{ name, address: '192.168.1.148', port: 8009, txt: { fn: 'Kitchen speaker', md: 'Google Home Mini' } }]
|
|
493
|
+
const renderers = await host.discover({ protocol: 'ssdp', searchTarget: 'urn:schemas-upnp-org:device:MediaRenderer:1' });
|
|
494
|
+
// [{ name: 'uuid:...', address: '192.168.1.176', location: 'http://192.168.1.176:44667/description.xml', server: '...' }]
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Each query must be listed exactly in `permissions.discovery`. Every address that
|
|
498
|
+
answers (and the host of an SSDP `location`) is then reachable by `fetch`, `socket`
|
|
499
|
+
and `tls` as though the operator had typed it in, including `verifyCertificate:
|
|
500
|
+
false`, until the plugin is reinitialised.
|
|
501
|
+
|
|
502
|
+
An empty answer is normal: a station in a container on a bridge network cannot see
|
|
503
|
+
multicast at all. Keep working from the addresses you were given, and do not
|
|
504
|
+
report "nothing found" as a fault.
|
|
505
|
+
|
|
454
506
|
## When your audio needs a helper to fetch it
|
|
455
507
|
|
|
456
508
|
Almost every provider answers `resolveStreamUrl` out of its own head: it knows a
|
|
@@ -896,6 +948,49 @@ takesArgs }`) each time the host starts listening on your plugin, for a platform
|
|
|
896
948
|
that lists commands in its own interface; overwrite, don't append. Leave it out
|
|
897
949
|
and people type the commands as they always could.
|
|
898
950
|
|
|
951
|
+
## Playing the station on a speaker
|
|
952
|
+
|
|
953
|
+
An `output` plugin puts the station on a Chromecast, a Sonos, a BluOS player or
|
|
954
|
+
anything else that can be told a URL and will fetch it. Five methods:
|
|
955
|
+
|
|
956
|
+
```ts
|
|
957
|
+
async listDevices(): Promise<OutputDevice[]> {
|
|
958
|
+
return this.configured.map(row => ({
|
|
959
|
+
id: row.address.toLowerCase(), name: row.name, address: row.address,
|
|
960
|
+
accepts: ['audio/mpeg', 'audio/aac'], followsMetadata: true,
|
|
961
|
+
}));
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
async play({ deviceId, url, contentType, metadata }: OutputPlayRequest): Promise<void> {
|
|
965
|
+
await this.device(deviceId).load(url, contentType, metadata); // resolves when accepted
|
|
966
|
+
}
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
`updateMetadata`, `stop` and `status` complete it. Four things are easy to get wrong.
|
|
970
|
+
|
|
971
|
+
**The speaker fetches the stream.** You are handed the mount's URL and its
|
|
972
|
+
content type and pass them on. Never build a station URL and never pick a format:
|
|
973
|
+
the host chooses the mount from what your device `accepts`, so list only what it
|
|
974
|
+
really plays (a Sonos takes MP3 and AAC for a radio URL and nothing else).
|
|
975
|
+
|
|
976
|
+
**The host owns retrying.** It remembers every cast it started, asks `status`
|
|
977
|
+
how each is doing, and plays one again when a device drops it. So `play`
|
|
978
|
+
resolves when the device ACCEPTED the command, not when sound comes out, and
|
|
979
|
+
you never reconnect a stream on your own.
|
|
980
|
+
|
|
981
|
+
**Warming up is not failing.** A live stream takes seconds to start. Report it
|
|
982
|
+
as `opening` or `buffering`, and a device that does not answer as `unreachable`
|
|
983
|
+
from `status` rather than a throw. List a configured device that does not
|
|
984
|
+
answer anyway: the operator asked for it by name.
|
|
985
|
+
|
|
986
|
+
**Stop means stop.** A speaker playing the station is a listener, and one left
|
|
987
|
+
playing holds the station's audience open. `stop` is idempotent: answer it for
|
|
988
|
+
a device that was not playing ours.
|
|
989
|
+
|
|
990
|
+
A device that only speaks a protocol where the sender streams the audio itself
|
|
991
|
+
(AirPlay audio, Bluetooth) cannot be an output: there is no URL to hand it, and
|
|
992
|
+
the station encodes nothing in its own process.
|
|
993
|
+
|
|
899
994
|
## Music providers
|
|
900
995
|
|
|
901
996
|
A `music-provider` declares any subset of four sub-capabilities and lists the
|
|
@@ -44,6 +44,7 @@ import type { NarrationPart, NarrationPiece, NarrationPiecesQuery, NarrationSeri
|
|
|
44
44
|
import type { NewsFeedDescriptor, NewsItem, NewsQuery } from './capabilities/news.js';
|
|
45
45
|
import type { PodcastAudio, PodcastDirectoryEntry, PodcastDirectoryQuery, PodcastEpisode, PodcastEpisodesQuery, PodcastShow } from './capabilities/podcast.js';
|
|
46
46
|
import type { InboundMessage, MessagingAction, MessagingAnnounceTarget, MessagingButton, MessagingCommand, MessagingReceiveQuery, MessagingReceiveResult, MessagingSendResult, MessagingSender, OutboundMessage } from './capabilities/messaging.js';
|
|
47
|
+
import type { OutputDevice, OutputMetadata, OutputMetadataRequest, OutputPlayRequest, OutputStatus } from './capabilities/output.js';
|
|
47
48
|
import type { ScrobblePlay, ScrobbleRejection, ScrobbleResult } from './capabilities/scrobble.js';
|
|
48
49
|
import type { SearchQuery, SearchResult } from './capabilities/search.js';
|
|
49
50
|
import type { ArtistTrack, SimilarArtist } from './capabilities/similarity.js';
|
|
@@ -53,7 +54,7 @@ import type { GetPlaylistTracksOptions, ListPlaylistsOptions, PlaybackState, Pro
|
|
|
53
54
|
import type { LlmMessage, LlmModelInfo, LlmRequest, LlmResult, LlmToolCall, LlmToolDeclaration, LlmUsage } from './capabilities/llm.js';
|
|
54
55
|
import type { SpeechLimits, SpeechRequest, SpeechVoice } from './capabilities/speech.js';
|
|
55
56
|
import type { ConfigField, ConfigFieldColumn, ConfigFieldOption, ConfigFieldPreset } from './plugin.config.fields.js';
|
|
56
|
-
import type { PlaylistTracksRequest, PluginSocketOptions, TrackFetchRequest, TrackFetchSession } from './plugin.host.js';
|
|
57
|
+
import type { DiscoveredService, DiscoveryOptions, DiscoveryQuery, PlaylistTracksRequest, PluginSocketOptions, PluginTlsOptions, TrackFetchRequest, TrackFetchSession } from './plugin.host.js';
|
|
57
58
|
import type { PluginConnectionResult } from './plugin.lifecycle.js';
|
|
58
59
|
import type { PluginManifest } from './plugin.manifest.js';
|
|
59
60
|
import type { NetworkPermissionFromConfig, NetworkPermissionHost, PluginGrantRequest, PluginPermissions } from './plugin.permissions.js';
|
|
@@ -121,6 +122,10 @@ export type AssertAllBoundaryPayloadsAreJsonSafe = AssertAllTrue<{
|
|
|
121
122
|
TrackFetchRequest: IsJsonSafe<TrackFetchRequest>;
|
|
122
123
|
PlaylistTracksRequest: IsJsonSafe<PlaylistTracksRequest>;
|
|
123
124
|
PluginSocketOptions: IsJsonSafe<PluginSocketOptions>;
|
|
125
|
+
PluginTlsOptions: IsJsonSafe<PluginTlsOptions>;
|
|
126
|
+
DiscoveryQuery: IsJsonSafe<DiscoveryQuery>;
|
|
127
|
+
DiscoveryOptions: IsJsonSafe<DiscoveryOptions>;
|
|
128
|
+
DiscoveredService: IsJsonSafe<DiscoveredService>;
|
|
124
129
|
SearchTracksOptions: IsJsonSafe<SearchTracksOptions>;
|
|
125
130
|
ListPlaylistsOptions: IsJsonSafe<ListPlaylistsOptions>;
|
|
126
131
|
GetPlaylistTracksOptions: IsJsonSafe<GetPlaylistTracksOptions>;
|
|
@@ -194,6 +199,11 @@ export type AssertAllBoundaryPayloadsAreJsonSafe = AssertAllTrue<{
|
|
|
194
199
|
MessagingSendResult: IsJsonSafe<MessagingSendResult>;
|
|
195
200
|
MessagingAnnounceTarget: IsJsonSafe<MessagingAnnounceTarget>;
|
|
196
201
|
MessagingCommand: IsJsonSafe<MessagingCommand>;
|
|
202
|
+
OutputDevice: IsJsonSafe<OutputDevice>;
|
|
203
|
+
OutputMetadata: IsJsonSafe<OutputMetadata>;
|
|
204
|
+
OutputPlayRequest: IsJsonSafe<OutputPlayRequest>;
|
|
205
|
+
OutputMetadataRequest: IsJsonSafe<OutputMetadataRequest>;
|
|
206
|
+
OutputStatus: IsJsonSafe<OutputStatus>;
|
|
197
207
|
SpeechLimits: IsJsonSafe<SpeechLimits>;
|
|
198
208
|
}>;
|
|
199
209
|
/**
|
|
@@ -201,7 +211,7 @@ export type AssertAllBoundaryPayloadsAreJsonSafe = AssertAllTrue<{
|
|
|
201
211
|
* registry-coverage test can compare it against what is actually exported
|
|
202
212
|
* from the boundary source files.
|
|
203
213
|
*/
|
|
204
|
-
export declare const JSON_SAFE_PAYLOAD_TYPES: readonly ["PluginConnectionResult", "PluginPermissions", "NetworkPermissionHost", "NetworkPermissionFromConfig", "PluginGrantRequest", "ConfigField", "ConfigFieldOption", "ConfigFieldColumn", "ConfigFieldPreset", "PluginManifest", "ProviderTrack", "ProviderPlaylist", "ProviderStream", "TrackFetchSession", "TrackFetchRequest", "PlaylistTracksRequest", "PluginSocketOptions", "SearchTracksOptions", "ListPlaylistsOptions", "GetPlaylistTracksOptions", "PlaybackState", "TrackRef", "ArtistRef", "AlbumRef", "ExternalId", "ExternalLink", "SourceDocument", "TrackEnrichment", "ArtistEnrichment", "AlbumEnrichment", "SpeechRequest", "SpeechVoice", "LlmMessage", "LlmToolDeclaration", "LlmToolCall", "LlmUsage", "LlmRequest", "LlmResult", "LlmModelInfo", "AnalysisRef", "AudioJoin", "AudioOverlay", "AudioTranscode", "TrackCuePoints", "TrackLoudness", "TrackTaggedLoudness", "TrackAnalysis", "ChartDescriptor", "ChartQuery", "ChartEntry", "NewsFeedDescriptor", "NewsQuery", "NewsItem", "NarrationSeries", "NarrationPiece", "NarrationPart", "NarrationText", "NarrationPiecesQuery", "NarrationTextQuery", "PodcastShow", "PodcastAudio", "PodcastEpisode", "PodcastEpisodesQuery", "PodcastDirectoryQuery", "PodcastDirectoryEntry", "SimilarArtist", "ArtistTrack", "SearchQuery", "SearchResult", "WeatherQuery", "WeatherConditions", "WeatherDay", "WeatherReading", "AlmanacQuery", "AlmanacSubject", "AlmanacEntry", "AlmanacDay", "ScrobblePlay", "ScrobbleRejection", "ScrobbleResult", "MessagingSender", "MessagingAction", "MessagingButton", "InboundMessage", "MessagingReceiveQuery", "MessagingReceiveResult", "OutboundMessage", "MessagingSendResult", "MessagingAnnounceTarget", "MessagingCommand", "SpeechLimits"];
|
|
214
|
+
export declare const JSON_SAFE_PAYLOAD_TYPES: readonly ["PluginConnectionResult", "PluginPermissions", "NetworkPermissionHost", "NetworkPermissionFromConfig", "PluginGrantRequest", "ConfigField", "ConfigFieldOption", "ConfigFieldColumn", "ConfigFieldPreset", "PluginManifest", "ProviderTrack", "ProviderPlaylist", "ProviderStream", "TrackFetchSession", "TrackFetchRequest", "PlaylistTracksRequest", "PluginSocketOptions", "PluginTlsOptions", "DiscoveryOptions", "DiscoveredService", "SearchTracksOptions", "ListPlaylistsOptions", "GetPlaylistTracksOptions", "PlaybackState", "TrackRef", "ArtistRef", "AlbumRef", "ExternalId", "ExternalLink", "SourceDocument", "TrackEnrichment", "ArtistEnrichment", "AlbumEnrichment", "SpeechRequest", "SpeechVoice", "LlmMessage", "LlmToolDeclaration", "LlmToolCall", "LlmUsage", "LlmRequest", "LlmResult", "LlmModelInfo", "AnalysisRef", "AudioJoin", "AudioOverlay", "AudioTranscode", "TrackCuePoints", "TrackLoudness", "TrackTaggedLoudness", "TrackAnalysis", "ChartDescriptor", "ChartQuery", "ChartEntry", "NewsFeedDescriptor", "NewsQuery", "NewsItem", "NarrationSeries", "NarrationPiece", "NarrationPart", "NarrationText", "NarrationPiecesQuery", "NarrationTextQuery", "PodcastShow", "PodcastAudio", "PodcastEpisode", "PodcastEpisodesQuery", "PodcastDirectoryQuery", "PodcastDirectoryEntry", "SimilarArtist", "ArtistTrack", "SearchQuery", "SearchResult", "WeatherQuery", "WeatherConditions", "WeatherDay", "WeatherReading", "AlmanacQuery", "AlmanacSubject", "AlmanacEntry", "AlmanacDay", "ScrobblePlay", "ScrobbleRejection", "ScrobbleResult", "MessagingSender", "MessagingAction", "MessagingButton", "InboundMessage", "MessagingReceiveQuery", "MessagingReceiveResult", "OutboundMessage", "MessagingSendResult", "MessagingAnnounceTarget", "MessagingCommand", "OutputDevice", "OutputMetadata", "OutputPlayRequest", "OutputMetadataRequest", "OutputStatus", "SpeechLimits"];
|
|
205
215
|
/**
|
|
206
216
|
* Boundary interfaces that are deliberately NOT payloads: they describe
|
|
207
217
|
* methods, so they carry functions by definition and can never be JSON-safe.
|
|
@@ -211,7 +221,7 @@ export declare const JSON_SAFE_PAYLOAD_TYPES: readonly ["PluginConnectionResult"
|
|
|
211
221
|
* interfaces explicitly is what makes "is this a payload or a contract?" a
|
|
212
222
|
* conscious decision for anyone adding one, rather than a silent omission.
|
|
213
223
|
*/
|
|
214
|
-
export declare const BOUNDARY_METHOD_TYPES: readonly ["PluginLogger", "PluginStorage", "PluginSecrets", "PluginConfigAccess", "PluginOAuth", "PluginEvents", "PluginTrackFetcher", "PluginSocket", "PluginHost", "PluginLifecycle", "MusicProviderCatalog", "MusicProviderStream", "MusicProviderSteer", "MusicProviderOAuth", "MusicProvider", "EnrichmentProvider", "SpeechPluginInstance", "LlmPluginInstance", "AnalysisProvider", "MixerProvider", "TranscodeProvider", "ChartsProvider", "NewsProvider", "NarrationProvider", "PodcastProvider", "SimilarityProvider", "SearchProvider", "WeatherProvider", "AlmanacProvider", "ScrobbleProvider", "MessagingProvider"];
|
|
224
|
+
export declare const BOUNDARY_METHOD_TYPES: readonly ["PluginLogger", "PluginStorage", "PluginSecrets", "PluginConfigAccess", "PluginOAuth", "PluginEvents", "PluginTrackFetcher", "PluginSocket", "PluginTlsSocket", "PluginHost", "PluginLifecycle", "MusicProviderCatalog", "MusicProviderStream", "MusicProviderSteer", "MusicProviderOAuth", "MusicProvider", "EnrichmentProvider", "SpeechPluginInstance", "LlmPluginInstance", "AnalysisProvider", "MixerProvider", "TranscodeProvider", "ChartsProvider", "NewsProvider", "NarrationProvider", "PodcastProvider", "SimilarityProvider", "SearchProvider", "WeatherProvider", "AlmanacProvider", "ScrobbleProvider", "MessagingProvider", "OutputProvider"];
|
|
215
225
|
/**
|
|
216
226
|
* Boundary interfaces that deliberately carry a LIVE object, and so are neither
|
|
217
227
|
* payloads nor method contracts.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boundary.json.safe.d.ts","sourceRoot":"","sources":["../src/boundary.json.safe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACxG,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjI,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACxF,OAAO,KAAK,EACR,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,kBAAkB,EACrB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EACR,YAAY,EACZ,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,oBAAoB,EACpB,WAAW,EACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EACR,cAAc,EACd,eAAe,EACf,uBAAuB,EACvB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,eAAe,EACf,eAAe,EAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAClG,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC7G,OAAO,KAAK,EACR,eAAe,EACf,QAAQ,EACR,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,eAAe,EACf,QAAQ,EACX,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EACR,wBAAwB,EACxB,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,mBAAmB,EACtB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACxI,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACtH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"boundary.json.safe.d.ts","sourceRoot":"","sources":["../src/boundary.json.safe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `output` kind. An output plugin puts the station on a speaker somewhere
|
|
3
|
+
* else: a Chromecast, a Sonos, a BluOS player, a DLNA renderer.
|
|
4
|
+
*
|
|
5
|
+
* ## The speaker fetches the stream, and nothing here carries audio
|
|
6
|
+
*
|
|
7
|
+
* Every speaker this describes is a PULL speaker: it is told a URL and fetches
|
|
8
|
+
* the station's mount itself, the way any other listener does. So the contract
|
|
9
|
+
* is commands and status, never bytes, and the station's rule that no audio is
|
|
10
|
+
* decoded or mixed in Node holds without an exception for it.
|
|
11
|
+
*
|
|
12
|
+
* That is also the line this capability does not cross. A PUSH protocol, where
|
|
13
|
+
* the sender encodes the audio and streams it to the device (AirPlay audio,
|
|
14
|
+
* Bluetooth), cannot implement it: there is no URL to hand over, and building
|
|
15
|
+
* one would put an encoder in the station's process. A speaker that only
|
|
16
|
+
* speaks such a protocol is out of reach of this capability on purpose, not by
|
|
17
|
+
* omission.
|
|
18
|
+
*
|
|
19
|
+
* ## A device is a listener
|
|
20
|
+
*
|
|
21
|
+
* A speaker playing the station is one more connection to the mount, and the
|
|
22
|
+
* station counts it as an audience like any other. That is the point rather
|
|
23
|
+
* than a side effect: a station with nobody listening may stand down, and a
|
|
24
|
+
* kitchen speaker is somebody listening. It is also why `stop` has to mean it:
|
|
25
|
+
* a device left playing holds the audience open.
|
|
26
|
+
*
|
|
27
|
+
* ## What the host decides, and what the plugin does
|
|
28
|
+
*
|
|
29
|
+
* The host chooses WHICH mount a device is given, from the content types the
|
|
30
|
+
* device says it {@link OutputDevice.accepts}, and builds the URL from the
|
|
31
|
+
* station's public address. A plugin never builds a station URL and never
|
|
32
|
+
* picks a format: it is handed both and passes them on. The host also owns
|
|
33
|
+
* whether a cast is still wanted: it remembers what it started, asks
|
|
34
|
+
* {@link OutputProvider.status} how each one is doing, and plays it again when
|
|
35
|
+
* a device drops it. So a plugin does not retry on its own, and should not:
|
|
36
|
+
* two things deciding to reconnect is one thing reconnecting twice.
|
|
37
|
+
*
|
|
38
|
+
* ## Status is the device's word, read honestly
|
|
39
|
+
*
|
|
40
|
+
* A speaker takes seconds to start a live stream, and reports a stream it has
|
|
41
|
+
* not started yet in whatever way it likes. {@link OutputPhase} is the shared
|
|
42
|
+
* vocabulary for that, and the rule for using it is that warming up is
|
|
43
|
+
* `opening` or `buffering`, never a failure, and a device that did not answer
|
|
44
|
+
* at all is `unreachable` rather than an exception: the host lists it all the
|
|
45
|
+
* same, so an operator sees the speaker they configured and why it is quiet.
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* Where a device is, as far as playing the station goes.
|
|
49
|
+
*
|
|
50
|
+
* - `idle`: answering, and playing nothing of ours.
|
|
51
|
+
* - `opening`: told to play, and has not started fetching yet.
|
|
52
|
+
* - `buffering`: fetching, and not yet making sound.
|
|
53
|
+
* - `playing`: making the station's sound.
|
|
54
|
+
* - `stopped`: was playing ours and has stopped, by request or on its own.
|
|
55
|
+
* - `unreachable`: did not answer.
|
|
56
|
+
*/
|
|
57
|
+
export type OutputPhase = 'idle' | 'opening' | 'buffering' | 'playing' | 'stopped' | 'unreachable';
|
|
58
|
+
/** One speaker a plugin can play the station on. */
|
|
59
|
+
export interface OutputDevice {
|
|
60
|
+
/**
|
|
61
|
+
* Stable and unique within this plugin, across restarts: the host stores it
|
|
62
|
+
* to resume a cast after a reboot, so an id that changes is a cast that is
|
|
63
|
+
* forgotten. Compare them case-insensitively if your sources disagree on
|
|
64
|
+
* case; the host does not.
|
|
65
|
+
*/
|
|
66
|
+
id: string;
|
|
67
|
+
/** What the operator calls it, as the device or the settings name it. */
|
|
68
|
+
name: string;
|
|
69
|
+
/** The make or model, where the device says. */
|
|
70
|
+
model?: string;
|
|
71
|
+
/**
|
|
72
|
+
* How the plugin reaches it, for the operator to recognise rather than for
|
|
73
|
+
* anybody to dial: an address, or a URL.
|
|
74
|
+
*/
|
|
75
|
+
address: string;
|
|
76
|
+
/**
|
|
77
|
+
* The protocol it is driven over, as a short word (`chromecast`, `upnp`,
|
|
78
|
+
* `bluos`), for a plugin that speaks several. Shown, never interpreted.
|
|
79
|
+
*/
|
|
80
|
+
protocol?: string;
|
|
81
|
+
/**
|
|
82
|
+
* The content types it can play, as MIME types (`audio/mpeg`, `audio/aac`,
|
|
83
|
+
* `audio/ogg`, `audio/flac`, `application/vnd.apple.mpegurl`). The host
|
|
84
|
+
* offers a device only the mounts it lists, so be honest: a Sonos takes MP3
|
|
85
|
+
* and AAC for a radio URL and nothing else, and listing more is a cast that
|
|
86
|
+
* fails on the device rather than here. Never empty: MP3 is the floor.
|
|
87
|
+
*/
|
|
88
|
+
accepts: string[];
|
|
89
|
+
/**
|
|
90
|
+
* Whether {@link OutputProvider.updateMetadata} changes what the device
|
|
91
|
+
* shows. `false` for a device that reads the stream's own titles, or one that
|
|
92
|
+
* can only be told at the start; the host then does not call it.
|
|
93
|
+
*/
|
|
94
|
+
followsMetadata: boolean;
|
|
95
|
+
}
|
|
96
|
+
/** What a device shows while it plays the station. */
|
|
97
|
+
export interface OutputMetadata {
|
|
98
|
+
/** The line it shows largest: the record, or the station's name. */
|
|
99
|
+
title: string;
|
|
100
|
+
/** The line under it: the artist, or the show. */
|
|
101
|
+
subtitle?: string;
|
|
102
|
+
/** An absolute `http(s)` URL the device fetches itself. */
|
|
103
|
+
artworkUrl?: string;
|
|
104
|
+
}
|
|
105
|
+
/** Play the station on one device. */
|
|
106
|
+
export interface OutputPlayRequest {
|
|
107
|
+
/** An {@link OutputDevice.id} this plugin listed. */
|
|
108
|
+
deviceId: string;
|
|
109
|
+
/** The mount, absolute, on the station's public address. Pass it on as it is. */
|
|
110
|
+
url: string;
|
|
111
|
+
/** The mount's content type, one the device said it {@link OutputDevice.accepts}. */
|
|
112
|
+
contentType: string;
|
|
113
|
+
/** What to show to begin with. */
|
|
114
|
+
metadata: OutputMetadata;
|
|
115
|
+
}
|
|
116
|
+
/** Change what a device shows, without restarting what it plays. */
|
|
117
|
+
export interface OutputMetadataRequest {
|
|
118
|
+
deviceId: string;
|
|
119
|
+
metadata: OutputMetadata;
|
|
120
|
+
}
|
|
121
|
+
/** How one device is doing. */
|
|
122
|
+
export interface OutputStatus {
|
|
123
|
+
deviceId: string;
|
|
124
|
+
phase: OutputPhase;
|
|
125
|
+
/** The URL it is playing, where it says; how the host tells ours from somebody else's. */
|
|
126
|
+
url?: string;
|
|
127
|
+
/** A sentence for the operator when the phase needs one, such as why it is unreachable. */
|
|
128
|
+
detail?: string;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The `output` capability's methods.
|
|
132
|
+
*
|
|
133
|
+
* Every method but {@link listDevices} names a device by the id
|
|
134
|
+
* {@link listDevices} gave it, and should answer for an id it does not know by
|
|
135
|
+
* throwing a `PluginError` with code `config`: the operator removed a speaker
|
|
136
|
+
* the host still remembered, and that is theirs to see.
|
|
137
|
+
*/
|
|
138
|
+
export interface OutputProvider {
|
|
139
|
+
/**
|
|
140
|
+
* Every speaker this plugin can play on: the ones the operator configured,
|
|
141
|
+
* and any it found. A configured device that does not answer is still
|
|
142
|
+
* listed, because the operator asked for it by name.
|
|
143
|
+
*/
|
|
144
|
+
listDevices(): Promise<OutputDevice[]>;
|
|
145
|
+
/**
|
|
146
|
+
* Start the station on a device, replacing whatever it was playing.
|
|
147
|
+
*
|
|
148
|
+
* Resolve once the device has ACCEPTED the command, not once it is making
|
|
149
|
+
* sound: starting a live stream takes seconds, and the host reads progress
|
|
150
|
+
* through {@link status}. Throw when the device refused or could not be
|
|
151
|
+
* reached.
|
|
152
|
+
*/
|
|
153
|
+
play(request: OutputPlayRequest): Promise<void>;
|
|
154
|
+
/** Change what a device shows. Called only for a device that {@link OutputDevice.followsMetadata}. */
|
|
155
|
+
updateMetadata(request: OutputMetadataRequest): Promise<void>;
|
|
156
|
+
/**
|
|
157
|
+
* Stop the station on a device. Resolve when it has stopped, or when it was
|
|
158
|
+
* not playing ours to begin with: stopping is idempotent.
|
|
159
|
+
*/
|
|
160
|
+
stop(deviceId: string): Promise<void>;
|
|
161
|
+
/**
|
|
162
|
+
* How a device is doing right now. Answer `unreachable` rather than
|
|
163
|
+
* throwing when it does not answer; throw only for an id this plugin does
|
|
164
|
+
* not know.
|
|
165
|
+
*/
|
|
166
|
+
status(deviceId: string): Promise<OutputStatus>;
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/capabilities/output.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAEnG,oDAAoD;AACpD,MAAM,WAAW,YAAY;IACzB;;;;;OAKG;IACH,EAAE,EAAE,MAAM,CAAC;IACX,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;CAC5B;AAED,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC3B,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAC9B,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,GAAG,EAAE,MAAM,CAAC;IACZ,qFAAqF;IACrF,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,QAAQ,EAAE,cAAc,CAAC;CAC5B;AAED,oEAAoE;AACpE,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,cAAc,CAAC;CAC5B;AAED,+BAA+B;AAC/B,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,0FAA0F;IAC1F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2FAA2F;IAC3F,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC3B;;;;OAIG;IACH,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAEvC;;;;;;;OAOG;IACH,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD,sGAAsG;IACtG,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9D;;;OAGG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACnD"}
|
package/dist/define.plugin.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { MessagingProvider } from './capabilities/messaging.js';
|
|
|
5
5
|
import type { MusicProviderCatalog, MusicProviderOAuth, MusicProviderSteer, MusicProviderStream } from './capabilities/music.provider.js';
|
|
6
6
|
import type { NarrationProvider } from './capabilities/narration.js';
|
|
7
7
|
import type { NewsProvider } from './capabilities/news.js';
|
|
8
|
+
import type { OutputProvider } from './capabilities/output.js';
|
|
8
9
|
import type { PodcastProvider } from './capabilities/podcast.js';
|
|
9
10
|
import type { ScrobbleProvider } from './capabilities/scrobble.js';
|
|
10
11
|
import type { SearchProvider } from './capabilities/search.js';
|
|
@@ -55,6 +56,8 @@ export type AlmanacPluginInstance = PluginLifecycle & AlmanacProvider;
|
|
|
55
56
|
export type ScrobblePluginInstance = PluginLifecycle & ScrobbleProvider;
|
|
56
57
|
/** Instance shape for a `messaging` plugin. */
|
|
57
58
|
export type MessagingPluginInstance = PluginLifecycle & MessagingProvider;
|
|
59
|
+
/** Instance shape for an `output` plugin. */
|
|
60
|
+
export type OutputPluginInstance = PluginLifecycle & OutputProvider;
|
|
58
61
|
/**
|
|
59
62
|
* Pairs a manifest with its factory and returns the object a plugin package
|
|
60
63
|
* default-exports. Purely a typing helper: it does no validation, because the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.plugin.d.ts","sourceRoot":"","sources":["../src/define.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC1I,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,eAAe,CAAC;AAE7C;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,SAAS,SAAS,cAAc,GAAG,cAAc,IAAI,MAAM,SAAS,CAAC;AAE/F,6CAA6C;AAC7C,MAAM,WAAW,aAAa,CAAC,SAAS,SAAS,cAAc,GAAG,cAAc;IAC5E,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;CACrC;AAED;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG,eAAe,GACrD,OAAO,CAAC,oBAAoB,CAAC,GAC7B,OAAO,CAAC,mBAAmB,CAAC,GAC5B,OAAO,CAAC,kBAAkB,CAAC,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAEhC,iDAAiD;AACjD,MAAM,MAAM,wBAAwB,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAE5E,4CAA4C;AAC5C,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAAG,cAAc,CAAC;AAEpE,0CAA0C;AAC1C,MAAM,MAAM,kBAAkB,GAAG,eAAe,GAAG,YAAY,CAAC;AAEhE,+CAA+C;AAC/C,MAAM,MAAM,uBAAuB,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAE1E,uGAAuG;AACvG,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG,eAAe,CAAC;AAEtE,gDAAgD;AAChD,MAAM,MAAM,wBAAwB,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAE5E,4CAA4C;AAC5C,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAAG,cAAc,CAAC;AAEpE,6CAA6C;AAC7C,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG,eAAe,CAAC;AAEtE,8CAA8C;AAC9C,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG,eAAe,CAAC;AAEtE,8CAA8C;AAC9C,MAAM,MAAM,sBAAsB,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAExE,+CAA+C;AAC/C,MAAM,MAAM,uBAAuB,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAE1E;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,SAAS,SAAS,cAAc,EACzD,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,GAClC,aAAa,CAAC,SAAS,CAAC,CAE1B"}
|
|
1
|
+
{"version":3,"file":"define.plugin.d.ts","sourceRoot":"","sources":["../src/define.plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './capabilities/mixer.js';
|
|
|
9
9
|
export * from './capabilities/music.provider.js';
|
|
10
10
|
export * from './capabilities/narration.js';
|
|
11
11
|
export * from './capabilities/news.js';
|
|
12
|
+
export * from './capabilities/output.js';
|
|
12
13
|
export * from './capabilities/podcast.js';
|
|
13
14
|
export * from './capabilities/scrobble.js';
|
|
14
15
|
export * from './capabilities/search.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,9 @@ var JSON_SAFE_PAYLOAD_TYPES = [
|
|
|
21
21
|
"TrackFetchRequest",
|
|
22
22
|
"PlaylistTracksRequest",
|
|
23
23
|
"PluginSocketOptions",
|
|
24
|
+
"PluginTlsOptions",
|
|
25
|
+
"DiscoveryOptions",
|
|
26
|
+
"DiscoveredService",
|
|
24
27
|
"SearchTracksOptions",
|
|
25
28
|
"ListPlaylistsOptions",
|
|
26
29
|
"GetPlaylistTracksOptions",
|
|
@@ -94,6 +97,11 @@ var JSON_SAFE_PAYLOAD_TYPES = [
|
|
|
94
97
|
"MessagingSendResult",
|
|
95
98
|
"MessagingAnnounceTarget",
|
|
96
99
|
"MessagingCommand",
|
|
100
|
+
"OutputDevice",
|
|
101
|
+
"OutputMetadata",
|
|
102
|
+
"OutputPlayRequest",
|
|
103
|
+
"OutputMetadataRequest",
|
|
104
|
+
"OutputStatus",
|
|
97
105
|
"SpeechLimits"
|
|
98
106
|
];
|
|
99
107
|
var BOUNDARY_METHOD_TYPES = [
|
|
@@ -105,6 +113,7 @@ var BOUNDARY_METHOD_TYPES = [
|
|
|
105
113
|
"PluginEvents",
|
|
106
114
|
"PluginTrackFetcher",
|
|
107
115
|
"PluginSocket",
|
|
116
|
+
"PluginTlsSocket",
|
|
108
117
|
"PluginHost",
|
|
109
118
|
"PluginLifecycle",
|
|
110
119
|
"MusicProviderCatalog",
|
|
@@ -127,7 +136,8 @@ var BOUNDARY_METHOD_TYPES = [
|
|
|
127
136
|
"WeatherProvider",
|
|
128
137
|
"AlmanacProvider",
|
|
129
138
|
"ScrobbleProvider",
|
|
130
|
-
"MessagingProvider"
|
|
139
|
+
"MessagingProvider",
|
|
140
|
+
"OutputProvider"
|
|
131
141
|
];
|
|
132
142
|
var BOUNDARY_LIVE_OBJECT_TYPES = [
|
|
133
143
|
// `signal`: the invocation's own `AbortSignal`, watched by `host.fetch` and
|
|
@@ -1206,6 +1216,17 @@ var pluginPermissionsSchema = z2.object({
|
|
|
1206
1216
|
oauth: z2.boolean(),
|
|
1207
1217
|
trackFetcher: z2.boolean().optional(),
|
|
1208
1218
|
sockets: z2.boolean().optional(),
|
|
1219
|
+
tls: z2.boolean().optional(),
|
|
1220
|
+
discovery: z2.array(z2.union([
|
|
1221
|
+
z2.object({
|
|
1222
|
+
protocol: z2.literal("mdns"),
|
|
1223
|
+
service: z2.string().min(1)
|
|
1224
|
+
}),
|
|
1225
|
+
z2.object({
|
|
1226
|
+
protocol: z2.literal("ssdp"),
|
|
1227
|
+
searchTarget: z2.string().min(1)
|
|
1228
|
+
})
|
|
1229
|
+
])).optional(),
|
|
1209
1230
|
grants: z2.array(grantRequestSchema).optional()
|
|
1210
1231
|
});
|
|
1211
1232
|
|
|
@@ -1230,6 +1251,7 @@ var PLUGIN_CAPABILITY_WEATHER = "weather";
|
|
|
1230
1251
|
var PLUGIN_CAPABILITY_ALMANAC = "almanac";
|
|
1231
1252
|
var PLUGIN_CAPABILITY_SCROBBLE = "scrobble";
|
|
1232
1253
|
var PLUGIN_CAPABILITY_MESSAGING = "messaging";
|
|
1254
|
+
var PLUGIN_CAPABILITY_OUTPUT = "output";
|
|
1233
1255
|
var KNOWN_PLUGIN_CAPABILITIES = [
|
|
1234
1256
|
PLUGIN_CAPABILITY_CATALOG,
|
|
1235
1257
|
PLUGIN_CAPABILITY_STREAM,
|
|
@@ -1250,7 +1272,8 @@ var KNOWN_PLUGIN_CAPABILITIES = [
|
|
|
1250
1272
|
PLUGIN_CAPABILITY_WEATHER,
|
|
1251
1273
|
PLUGIN_CAPABILITY_ALMANAC,
|
|
1252
1274
|
PLUGIN_CAPABILITY_SCROBBLE,
|
|
1253
|
-
PLUGIN_CAPABILITY_MESSAGING
|
|
1275
|
+
PLUGIN_CAPABILITY_MESSAGING,
|
|
1276
|
+
PLUGIN_CAPABILITY_OUTPUT
|
|
1254
1277
|
];
|
|
1255
1278
|
function isZodSchema(value) {
|
|
1256
1279
|
if (value instanceof z3.ZodType) return true;
|
|
@@ -1300,6 +1323,7 @@ export {
|
|
|
1300
1323
|
PLUGIN_CAPABILITY_NARRATION,
|
|
1301
1324
|
PLUGIN_CAPABILITY_NEWS,
|
|
1302
1325
|
PLUGIN_CAPABILITY_OAUTH,
|
|
1326
|
+
PLUGIN_CAPABILITY_OUTPUT,
|
|
1303
1327
|
PLUGIN_CAPABILITY_PODCAST,
|
|
1304
1328
|
PLUGIN_CAPABILITY_SCROBBLE,
|
|
1305
1329
|
PLUGIN_CAPABILITY_SEARCH,
|