@voxgig/station 0.0.2 → 0.2.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 +26 -32
- package/dist/src/Station.d.ts +1 -133
- package/dist/src/Station.js +46 -434
- package/dist/src/Station.js.map +1 -1
- package/dist/src/adapter.js +0 -54
- package/dist/src/adapter.js.map +1 -1
- package/dist/src/config-shape.js +0 -11
- package/dist/src/config-shape.js.map +1 -1
- package/dist/src/descriptor.js +0 -36
- package/dist/src/descriptor.js.map +1 -1
- package/dist/src/error.js +0 -5
- package/dist/src/error.js.map +1 -1
- package/dist/src/factory.d.ts +0 -9
- package/dist/src/factory.js +0 -37
- package/dist/src/factory.js.map +1 -1
- package/dist/src/feature.d.ts +0 -75
- package/dist/src/feature.js +0 -87
- package/dist/src/feature.js.map +1 -1
- package/dist/src/index.d.ts +1 -2
- package/dist/src/index.js +11 -22
- package/dist/src/index.js.map +1 -1
- package/dist/src/loader.d.ts +0 -29
- package/dist/src/loader.js +0 -66
- package/dist/src/loader.js.map +1 -1
- package/dist/src/profile.d.ts +10 -3
- package/dist/src/profile.js +97 -23
- package/dist/src/profile.js.map +1 -1
- package/dist/src/secrets.d.ts +5 -0
- package/dist/src/secrets.js +106 -32
- package/dist/src/secrets.js.map +1 -1
- package/dist/src/shape.d.ts +0 -22
- package/dist/src/shape.js +0 -113
- package/dist/src/shape.js.map +1 -1
- package/package.json +3 -4
- package/src/Station.ts +34 -441
- package/src/adapter.ts +0 -57
- package/src/config-shape.ts +0 -11
- package/src/descriptor.ts +0 -36
- package/src/error.ts +0 -5
- package/src/factory.ts +0 -37
- package/src/feature.ts +0 -87
- package/src/index.ts +1 -14
- package/src/loader.ts +0 -66
- package/src/profile.ts +115 -23
- package/src/secrets.ts +104 -32
- package/src/shape.ts +0 -113
- package/src/types.ts +0 -59
- package/dist/src/index.browser.d.ts +0 -14
- package/dist/src/index.browser.js +0 -64
- package/dist/src/index.browser.js.map +0 -1
- package/dist/src/profilecore.d.ts +0 -10
- package/dist/src/profilecore.js +0 -180
- package/dist/src/profilecore.js.map +0 -1
- package/src/index.browser.ts +0 -56
- package/src/profilecore.ts +0 -201
package/README.md
CHANGED
|
@@ -16,42 +16,37 @@ validates through [voxgig/struct](https://github.com/voxgig/struct).
|
|
|
16
16
|
Those are the only two runtime dependencies a station library takes
|
|
17
17
|
(design §10).
|
|
18
18
|
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
`package.json` `exports`
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
`
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
On the browser entry `Station.open()` takes `config` as an object — the
|
|
44
|
-
explicit-config path, which skips file loading entirely. With no `config`
|
|
45
|
-
it behaves as node does when no `station.json` exists: null config,
|
|
46
|
-
repo-scoped.
|
|
19
|
+
## One entry
|
|
20
|
+
|
|
21
|
+
`package.json` `exports` names a single entry, `dist/src/index.js`.
|
|
22
|
+
|
|
23
|
+
There used to be two. A `browser` condition selected
|
|
24
|
+
`dist/src/index.browser.js` — the same surface **minus** the file-loading
|
|
25
|
+
half, so that no `node:` builtin was reachable from it — and three pieces
|
|
26
|
+
of machinery existed to keep that true: `profilecore.ts` held the pure
|
|
27
|
+
half of profile handling so the browser entry could reach it without
|
|
28
|
+
`node:fs`; `Station.ts` took `loadConfig`/`configScope` through a
|
|
29
|
+
`ConfigFileIO` seam that only the node entry registered; and
|
|
30
|
+
`test/browser.test.ts` walked the compiled `dist` graph asserting no
|
|
31
|
+
`node:` builtin appeared.
|
|
32
|
+
|
|
33
|
+
**Station is server-side only**, so all of it is gone: the second entry,
|
|
34
|
+
the condition, the seam, the split and the graph-walk test.
|
|
35
|
+
`profilecore.ts` is merged back into `profile.ts`, and `Station.ts`
|
|
36
|
+
imports `loadConfig` and `configScope` directly. Every import of
|
|
37
|
+
`./profile` is unchanged — that path always re-exported the pure half.
|
|
38
|
+
|
|
39
|
+
`setConfigFileIO` and its `ConfigFileIO` type were exported from this
|
|
40
|
+
package and are removed with the seam. Nothing in this repository or any
|
|
41
|
+
other voxgig port used them; the seam existed for the browser entry and
|
|
42
|
+
for nothing else.
|
|
47
43
|
|
|
48
44
|
## Layout
|
|
49
45
|
|
|
50
46
|
| | |
|
|
51
47
|
|---|---|
|
|
52
48
|
| `src/Station.ts` | the core: open/connect/adopt/options, sdk/create/check/warm, registry, transport middleware, the ref grammar |
|
|
53
|
-
| `src/index.ts` | the
|
|
54
|
-
| `src/index.browser.ts` | the browser entry (above) |
|
|
49
|
+
| `src/index.ts` | the entry: the public surface |
|
|
55
50
|
| `src/adapter.ts` | `featureBinding` (the one binding entry) + the carried adapter |
|
|
56
51
|
| `src/shape.ts` | `normalizeConfig`/`validateConfig`: the §4 grammar, the §4.4 workarounds, the §5.2 credential scans |
|
|
57
52
|
| `src/config-shape.ts` | a verbatim mirror of [`spec/config-shape.json`](../spec/config-shape.json) — generated by `make sync-shape`, never edited by hand |
|
|
@@ -60,8 +55,7 @@ repo-scoped.
|
|
|
60
55
|
| `src/loader.ts` | `loadSync`/`loadAsync`: CommonJS require + guarded dynamic import (§6.3) |
|
|
61
56
|
| `src/descriptor.ts` | descriptor v1 normalizer + canonical serializer |
|
|
62
57
|
| `src/secrets.ts` | the sekreto-backed broker + the placeholder |
|
|
63
|
-
| `src/profile.ts` | the
|
|
64
|
-
| `src/profilecore.ts` | the pure half: profile selection, ref grammar, the §3.3 merge |
|
|
58
|
+
| `src/profile.ts` | profile selection, the ref grammar, the §3.3 merge, `station.json` lookup and config scope |
|
|
65
59
|
| `src/events.ts` | the bounded event ring + tap |
|
|
66
60
|
| `src/error.ts` | the error-code catalog |
|
|
67
61
|
| `src/types.ts` | shared types; the descriptor and event shapes are pinned by the corpus, so evolve them additively |
|
package/dist/src/Station.d.ts
CHANGED
|
@@ -1,51 +1,10 @@
|
|
|
1
1
|
import { Binding, PluginEntry, ResolvedInstance, SdkBlock, StationEvent, StationOptions } from './types';
|
|
2
|
-
/** The FILE half of config loading, behind a seam so this module never
|
|
3
|
-
* imports it (§2.2, §17 Phase 1: no top-level `node:` imports reachable
|
|
4
|
-
* from the browser entry). The NODE entry (`index.ts`) registers
|
|
5
|
-
* `profile.ts`'s loadConfig/configScope at module load; the browser
|
|
6
|
-
* entry registers nothing, so a browser `open()` with no explicit
|
|
7
|
-
* `config` behaves exactly as node does when no station.json exists -
|
|
8
|
-
* null config, repo-scoped - rather than inventing a third state.
|
|
9
|
-
* Passing `config` (the documented browser spelling, §2.2) skips the
|
|
10
|
-
* seam entirely on both entries, which is the pre-existing
|
|
11
|
-
* explicit-config path unchanged. */
|
|
12
|
-
export type ConfigFileIO = {
|
|
13
|
-
loadConfig: (from?: string) => any;
|
|
14
|
-
configScope: (from?: string) => 'repo' | 'user' | 'none';
|
|
15
|
-
};
|
|
16
|
-
export declare function setConfigFileIO(io: ConfigFileIO): void;
|
|
17
|
-
/** §6.1: `as` IS A TAG, NOT A FREE NAME.
|
|
18
|
-
*
|
|
19
|
-
* The api comes from the SDK being passed, so the resulting ref is
|
|
20
|
-
* `<api>$<tag>` and multi-instance works imperatively too. A full ref is
|
|
21
|
-
* also accepted and is VALIDATED: its name must equal the SDK's api
|
|
22
|
-
* slug, or it is `station_instance_api`.
|
|
23
|
-
*
|
|
24
|
-
* Both forms are needed because the imperative path is where the api is
|
|
25
|
-
* implicit in an argument rather than written in a key. An `as` that
|
|
26
|
-
* took an arbitrary name would reintroduce exactly the second-identity
|
|
27
|
-
* problem the ref re-key removed: under the ref invariant
|
|
28
|
-
* `as: 'solar-eu'` would denote the untagged `solar-eu` DEFINITION, not
|
|
29
|
-
* an instance of the SDK just handed in, and registry grouping, api
|
|
30
|
-
* defaults and every ref consumer would disagree about what it is.
|
|
31
|
-
*
|
|
32
|
-
* A bare connect(SDK) with no name falls back to the descriptor slug,
|
|
33
|
-
* which is today's behaviour and why the single-instance case is
|
|
34
|
-
* unchanged to the byte. */
|
|
35
2
|
export declare function instanceRef(api: string, fopts?: any): string;
|
|
36
3
|
export declare function checkInstanceName(name: string): boolean;
|
|
37
4
|
export declare function checkInstanceTag(tag: string): boolean;
|
|
38
5
|
export declare class Station {
|
|
39
6
|
private static ambient;
|
|
40
7
|
private static ambientOpts;
|
|
41
|
-
/** §6.2's second path, and the front door the docs name.
|
|
42
|
-
*
|
|
43
|
-
* The package exported only the free `provide()` and the class had no
|
|
44
|
-
* static — so the documented `Station.provide(...)` call failed, and
|
|
45
|
-
* so did the remediation `station_no_factory` prints, which tells the
|
|
46
|
-
* user to make exactly that call. Delegates to the same
|
|
47
|
-
* process-global table the free function fills; there is one
|
|
48
|
-
* registry, not two. */
|
|
49
8
|
static provide(api: string, factory: any): void;
|
|
50
9
|
private opts;
|
|
51
10
|
private profile;
|
|
@@ -71,51 +30,17 @@ export declare class Station {
|
|
|
71
30
|
private construct;
|
|
72
31
|
options(a?: any, b?: any): any;
|
|
73
32
|
_boundEntry(client: any): PluginEntry | null;
|
|
74
|
-
/** The profile block that governs an instance — its own if the
|
|
75
|
-
* profile declares it, otherwise its **api's**.
|
|
76
|
-
*
|
|
77
|
-
* `resolveProfile` builds `profile.sdk` from the declared refs alone
|
|
78
|
-
* ("an api block declares no instance, so the ref set comes from the
|
|
79
|
-
* two `sdk` maps"), shallow-merging `profile.api[a]` into each. That
|
|
80
|
-
* is right for a declared instance and leaves an IMPERATIVE one —
|
|
81
|
-
* `connect(SDK, { as: 'test' })`, named but never written into
|
|
82
|
-
* config — with no block at all. The api-level `secret`, `base` and
|
|
83
|
-
* most seriously `policy.hosts` then did not reach it, so a profile
|
|
84
|
-
* that denies egress everywhere denied nothing for a tagged client.
|
|
85
|
-
*
|
|
86
|
-
* ONE RULE, ONE PLACE: registration and the transport seam both ask
|
|
87
|
-
* here, because they disagreeing is how the credential and the
|
|
88
|
-
* allowlist came apart in the first place. */
|
|
89
33
|
private blockFor;
|
|
90
|
-
/** The DECLARED instance an assigned tag stands for, or the name
|
|
91
|
-
* itself. `create('stripe$prod')` registers under `stripe$1`, and
|
|
92
|
-
* every question about that client's configuration — its secret, its
|
|
93
|
-
* base, its egress policy — is a question about `stripe$prod`. */
|
|
94
34
|
private declaredRef;
|
|
95
35
|
_register(client: any, config: any, options: any, _calleropts: any, fopts?: any): {
|
|
96
36
|
binding: Binding;
|
|
97
37
|
profilePlugin?: SdkBlock;
|
|
98
38
|
};
|
|
99
39
|
private descriptorCache;
|
|
100
|
-
/** The descriptor describes the API, and is SHARED by every instance
|
|
101
|
-
* of it — which is §7.4's own reasoning for why the effective secret
|
|
102
|
-
* name moved to `Binding` and is not read off the descriptor.
|
|
103
|
-
*
|
|
104
|
-
* The same argument applies to feature activation, and this did not
|
|
105
|
-
* follow it: the cache is keyed by slug alone while
|
|
106
|
-
* `normalizeDescriptor`'s second argument decides each feature row's
|
|
107
|
-
* `active`. So two instances of one api constructed with different
|
|
108
|
-
* feature maps shared the FIRST one's feature state, and
|
|
109
|
-
* `descriptorOf()` / `canonicalDescriptor()` became
|
|
110
|
-
* construction-order-dependent.
|
|
111
|
-
*
|
|
112
|
-
* Normalized with no per-instance features, so the shared value holds
|
|
113
|
-
* only API-stable metadata — which is what `factory.ts` already does
|
|
114
|
-
* when it normalizes at provide time. Per-instance activation is
|
|
115
|
-
* `featuresOf(name)`'s answer, and always was. */
|
|
116
40
|
private describe;
|
|
117
41
|
_hoist(name: string, value: string): void;
|
|
118
42
|
_transport(name: string, inner: any, fctx: any, fullurl: string, fetchdef: any): Promise<any>;
|
|
43
|
+
private scrubbed;
|
|
119
44
|
private emitHttp;
|
|
120
45
|
private emitErr;
|
|
121
46
|
_opEvent(name: string, ctx: any, outcome: string): void;
|
|
@@ -128,63 +53,16 @@ export declare class Station {
|
|
|
128
53
|
secretname?: string;
|
|
129
54
|
warnings: string[];
|
|
130
55
|
}[];
|
|
131
|
-
/** The instance, constructed on first call and CACHED: same name ->
|
|
132
|
-
* same object. That caching is what makes "get it where you need it"
|
|
133
|
-
* a real instruction - call it in a request handler, in a worker, in
|
|
134
|
-
* a test, and the first call pays construction while the rest are a
|
|
135
|
-
* map lookup.
|
|
136
|
-
*
|
|
137
|
-
* SYNCHRONOUS (§6.3), which is what bounds the loader to CommonJS. */
|
|
138
56
|
sdk(name: string): any;
|
|
139
|
-
/** An UNCACHED client from the same resolved config plus overrides,
|
|
140
|
-
* for the case that genuinely wants a distinct one - a per-request
|
|
141
|
-
* credential scope, a test double. Deliberately the longer name.
|
|
142
|
-
*
|
|
143
|
-
* It registers under an AUTO-ASSIGNED TAG, because §7.5 registers
|
|
144
|
-
* every constructed adapter under its instance name and
|
|
145
|
-
* `station_bound_twice` fires on a second binding of one name: a
|
|
146
|
-
* second `create('stripe')` would otherwise throw, which is exactly
|
|
147
|
-
* the per-request case this exists for. The tag is the lowest unused
|
|
148
|
-
* positive integer, so an auto-tagged instance is an ORDINARY
|
|
149
|
-
* instance rather than a parallel identity scheme - `plugins()`, the
|
|
150
|
-
* placeholder, the event stream and `station_bound_twice` all keep
|
|
151
|
-
* working on one identity model.
|
|
152
|
-
*
|
|
153
|
-
* The SECRET NAME does not follow the assigned tag: it resolves from
|
|
154
|
-
* the DECLARED instance the tag was assigned under, so every client
|
|
155
|
-
* of one instance shares one broker cache entry rather than
|
|
156
|
-
* re-resolving per request (§5.3). */
|
|
157
57
|
create(name: string, overrides?: any): any;
|
|
158
|
-
/** The lowest positive integer tag not already taken, by a LIVE
|
|
159
|
-
* instance or a DECLARED one.
|
|
160
|
-
*
|
|
161
|
-
* The registry alone was not enough: a profile may declare
|
|
162
|
-
* `stripe$1`, and until something constructs it `registry.has` says
|
|
163
|
-
* false — so `create('stripe$prod')` took that identity for a client
|
|
164
|
-
* built from the `stripe$prod` block. `instances()` then reported the
|
|
165
|
-
* declared `stripe$1` as live with the wrong client, and a later
|
|
166
|
-
* `sdk('stripe$1')` failed `station_bound_twice` against a binding
|
|
167
|
-
* that was never its own. Declaration reserves the name whether or
|
|
168
|
-
* not it has been built. */
|
|
169
58
|
private autotag;
|
|
170
59
|
private build;
|
|
171
|
-
/** §6.2's three paths, in order of preference: self-registration,
|
|
172
|
-
* `Station.provide`, then the loader. */
|
|
173
60
|
private resolveFactory;
|
|
174
|
-
/** `package` is honoured only from repo-scoped config (§6.3), and a
|
|
175
|
-
* user-level one is IGNORED WITH A WARNING rather than imported - it
|
|
176
|
-
* names code to load and sits outside the repo's review boundary. */
|
|
177
61
|
private loaderPackage;
|
|
178
62
|
/** ts/js only: preload ESM packages into the factory table, after
|
|
179
63
|
* which `sdk()` is synchronous again for everything (§6.3). One
|
|
180
64
|
* `await` at startup rather than one per call site. */
|
|
181
65
|
load(): Promise<void>;
|
|
182
|
-
/** The merged, ordered feature set for one instance, WITH
|
|
183
|
-
* PROVENANCE (§8.7): which config level set each value.
|
|
184
|
-
*
|
|
185
|
-
* Provenance is the half that makes a fleet view usable rather than
|
|
186
|
-
* merely correct - at 26 instances "why is retry off here" is the
|
|
187
|
-
* question, and a merged map alone cannot answer it. */
|
|
188
66
|
featuresOf(name: string): {
|
|
189
67
|
ordered: string[];
|
|
190
68
|
merged: {
|
|
@@ -203,10 +81,6 @@ export declare class Station {
|
|
|
203
81
|
api?: string;
|
|
204
82
|
feature?: string;
|
|
205
83
|
}): any[];
|
|
206
|
-
/** Eagerly resolve and construct every ACTIVE instance - for CI
|
|
207
|
-
* (§6.6). The point is to turn availability errors, which are
|
|
208
|
-
* deliberately deferred to first use, into one failure at a moment
|
|
209
|
-
* somebody is watching. */
|
|
210
84
|
check(): {
|
|
211
85
|
ok: string[];
|
|
212
86
|
failed: {
|
|
@@ -215,12 +89,6 @@ export declare class Station {
|
|
|
215
89
|
message: string;
|
|
216
90
|
}[];
|
|
217
91
|
};
|
|
218
|
-
/** Batch-resolve secrets for ACTIVE instances (§5.5).
|
|
219
|
-
*
|
|
220
|
-
* With no argument it warms the active ones only, because reaching
|
|
221
|
-
* for a credential belonging to a disabled integration is the wrong
|
|
222
|
-
* default. `warm(names)` warms exactly what it is given, inactive
|
|
223
|
-
* included, because an explicit name is an explicit request. */
|
|
224
92
|
warm(names?: string[]): Promise<{
|
|
225
93
|
warmed: string[];
|
|
226
94
|
missed: string[];
|