@voxgig/station 0.0.1
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/LICENSE +21 -0
- package/README.md +88 -0
- package/dist/src/Station.d.ts +238 -0
- package/dist/src/Station.js +1213 -0
- package/dist/src/Station.js.map +1 -0
- package/dist/src/adapter.d.ts +9 -0
- package/dist/src/adapter.js +171 -0
- package/dist/src/adapter.js.map +1 -0
- package/dist/src/config-shape.d.ts +1 -0
- package/dist/src/config-shape.js +329 -0
- package/dist/src/config-shape.js.map +1 -0
- package/dist/src/descriptor.d.ts +8 -0
- package/dist/src/descriptor.js +170 -0
- package/dist/src/descriptor.js.map +1 -0
- package/dist/src/error.d.ts +8 -0
- package/dist/src/error.js +60 -0
- package/dist/src/error.js.map +1 -0
- package/dist/src/events.d.ts +15 -0
- package/dist/src/events.js +46 -0
- package/dist/src/events.js.map +1 -0
- package/dist/src/factory.d.ts +24 -0
- package/dist/src/factory.js +79 -0
- package/dist/src/factory.js.map +1 -0
- package/dist/src/feature.d.ts +106 -0
- package/dist/src/feature.js +324 -0
- package/dist/src/feature.js.map +1 -0
- package/dist/src/index.browser.d.ts +14 -0
- package/dist/src/index.browser.js +64 -0
- package/dist/src/index.browser.js.map +1 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.js +56 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/loader.d.ts +45 -0
- package/dist/src/loader.js +181 -0
- package/dist/src/loader.js.map +1 -0
- package/dist/src/profile.d.ts +6 -0
- package/dist/src/profile.js +77 -0
- package/dist/src/profile.js.map +1 -0
- package/dist/src/profilecore.d.ts +10 -0
- package/dist/src/profilecore.js +180 -0
- package/dist/src/profilecore.js.map +1 -0
- package/dist/src/secrets.d.ts +12 -0
- package/dist/src/secrets.js +93 -0
- package/dist/src/secrets.js.map +1 -0
- package/dist/src/shape.d.ts +42 -0
- package/dist/src/shape.js +444 -0
- package/dist/src/shape.js.map +1 -0
- package/dist/src/types.d.ts +138 -0
- package/dist/src/types.js +5 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +60 -0
- package/src/Station.ts +1310 -0
- package/src/adapter.ts +183 -0
- package/src/config-shape.ts +326 -0
- package/src/descriptor.ts +179 -0
- package/src/error.ts +64 -0
- package/src/events.ts +45 -0
- package/src/factory.ts +93 -0
- package/src/feature.ts +321 -0
- package/src/index.browser.ts +56 -0
- package/src/index.ts +50 -0
- package/src/loader.ts +188 -0
- package/src/profile.ts +67 -0
- package/src/profilecore.ts +201 -0
- package/src/secrets.ts +96 -0
- package/src/shape.ts +435 -0
- package/src/types.ts +185 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.envtoken = envtoken;
|
|
4
|
+
exports.secretnameDefault = secretnameDefault;
|
|
5
|
+
exports.normalizeDescriptor = normalizeDescriptor;
|
|
6
|
+
exports.canonicalSerialize = canonicalSerialize;
|
|
7
|
+
// The ONLY way to build an env-var token in station, mirroring sdkgen's
|
|
8
|
+
// packageMeta envToken exactly: 'gnarly-pets' -> 'GNARLY_PETS'. The
|
|
9
|
+
// `secretname` corpus section pins the round-trip against sekreto's
|
|
10
|
+
// envkey() and sdkgen's envName() - the one place three grammars meet.
|
|
11
|
+
function envtoken(name) {
|
|
12
|
+
return String(name || '')
|
|
13
|
+
.toUpperCase().replace(/[^A-Z0-9]+/g, '_').replace(/^_+|_+$/g, '');
|
|
14
|
+
}
|
|
15
|
+
// The default sekreto name for a plugin (design §5.1): envtoken(slug)
|
|
16
|
+
// lowercased, plus '.apikey'. sekreto's envkey() then yields exactly the
|
|
17
|
+
// env var the SDK's README documents: gnarly_pets.apikey -> GNARLY_PETS_APIKEY.
|
|
18
|
+
function secretnameDefault(slug) {
|
|
19
|
+
return envtoken(slug).toLowerCase() + '.apikey';
|
|
20
|
+
}
|
|
21
|
+
// Best-effort slug from a camel name, for SDKs whose embedded config
|
|
22
|
+
// predates main.slug (design §4 legacy sentinels). The hyphen caveat is
|
|
23
|
+
// real: 'VoxgigSolardemo' -> 'voxgigsolardemo', NOT 'voxgig-solardemo' -
|
|
24
|
+
// callers surface a warning event when this path is taken.
|
|
25
|
+
function legacySlug(name) {
|
|
26
|
+
return String(name || '').toLowerCase();
|
|
27
|
+
}
|
|
28
|
+
// Normalize a generated SDK's embedded config into descriptor v1
|
|
29
|
+
// (design §4). The config is the one every SDK carries (Config.main /
|
|
30
|
+
// .feature / .options / .entity); the descriptor is a VIEW over it.
|
|
31
|
+
// Returns the descriptor plus any legacy warnings.
|
|
32
|
+
function normalizeDescriptor(config, activeFeatures) {
|
|
33
|
+
const warnings = [];
|
|
34
|
+
const main = config?.main || {};
|
|
35
|
+
const options = config?.options || {};
|
|
36
|
+
const name = String(main.name || '');
|
|
37
|
+
let slug = main.slug;
|
|
38
|
+
if (null == slug || '' === slug) {
|
|
39
|
+
slug = legacySlug(name);
|
|
40
|
+
warnings.push('descriptor: legacy config has no main.slug; derived "' +
|
|
41
|
+
slug + '" from the camel name - hyphens in the original name are lost');
|
|
42
|
+
}
|
|
43
|
+
const version = null != main.version ? String(main.version) : '0.0.0';
|
|
44
|
+
const target = null != main.target ? String(main.target) : 'unknown';
|
|
45
|
+
const server = [];
|
|
46
|
+
const svr = options.server || {};
|
|
47
|
+
for (const k of Object.keys(svr).sort()) {
|
|
48
|
+
server.push({ name: k, value: String(svr[k]) });
|
|
49
|
+
}
|
|
50
|
+
const authActive = null != options.auth;
|
|
51
|
+
const auth = {
|
|
52
|
+
active: authActive,
|
|
53
|
+
prefix: authActive ? String(options.auth.prefix || '') : '',
|
|
54
|
+
secretname: secretnameDefault(slug),
|
|
55
|
+
};
|
|
56
|
+
const entities = {};
|
|
57
|
+
const entdefs = config?.entity || {};
|
|
58
|
+
for (const ename of Object.keys(entdefs).sort()) {
|
|
59
|
+
const e = entdefs[ename] || {};
|
|
60
|
+
const fields = {};
|
|
61
|
+
for (const f of e.fields || []) {
|
|
62
|
+
if (null != f && null != f.name) {
|
|
63
|
+
fields[f.name] = { kind: String(f.kind || f.type || '') };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const ops = {};
|
|
67
|
+
const opdefs = e.op || {};
|
|
68
|
+
for (const opname of Object.keys(opdefs).sort()) {
|
|
69
|
+
const op = opdefs[opname] || {};
|
|
70
|
+
const points = [];
|
|
71
|
+
for (const p of op.points || []) {
|
|
72
|
+
if (null == p) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const point = {
|
|
76
|
+
method: String(p.method || ''),
|
|
77
|
+
path: String(p.orig || p.path || ''),
|
|
78
|
+
params: (p.parts || []).filter((s) => 'string' === typeof s &&
|
|
79
|
+
s.startsWith(':')).map((s) => s.slice(1)),
|
|
80
|
+
};
|
|
81
|
+
if (null != p.select) {
|
|
82
|
+
point.select = p.select;
|
|
83
|
+
}
|
|
84
|
+
points.push(point);
|
|
85
|
+
}
|
|
86
|
+
ops[opname] = { points };
|
|
87
|
+
}
|
|
88
|
+
entities[ename] = { fields, ops };
|
|
89
|
+
}
|
|
90
|
+
// §7.4: the features list gains `options` and `transport`, because
|
|
91
|
+
// it was throwing away what the SDK already embeds -
|
|
92
|
+
// `config.feature[name].options` is the feature's own declared key
|
|
93
|
+
// set WITH TYPED DEFAULTS, which is the schema §8.5 validates
|
|
94
|
+
// against, and `transport` is the role §8.4 orders by.
|
|
95
|
+
//
|
|
96
|
+
// Both are already inside the SDK; the descriptor stops discarding
|
|
97
|
+
// them. ADDITIVE, so descriptor v1 consumers are unaffected.
|
|
98
|
+
//
|
|
99
|
+
// `transport` is carried rather than inferred: the obvious signal, an
|
|
100
|
+
// empty `hook: {}`, is wrong for station, which both wraps AND
|
|
101
|
+
// dispatches hooks. Absent until sdkgen emits it (§11 items 6-7), and
|
|
102
|
+
// §8.4's role checks degrade to nothing until then rather than
|
|
103
|
+
// guessing.
|
|
104
|
+
const features = [];
|
|
105
|
+
const fdefs = config?.feature || {};
|
|
106
|
+
const factive = activeFeatures || {};
|
|
107
|
+
for (const fname of Object.keys(fdefs).sort()) {
|
|
108
|
+
const fdef = fdefs[fname] || {};
|
|
109
|
+
const row = { name: fname, active: true === factive[fname]?.active };
|
|
110
|
+
if (null != fdef.options && 'object' === typeof fdef.options) {
|
|
111
|
+
row.options = fdef.options;
|
|
112
|
+
}
|
|
113
|
+
if (null != fdef.transport && '' !== fdef.transport) {
|
|
114
|
+
row.transport = String(fdef.transport);
|
|
115
|
+
}
|
|
116
|
+
features.push(row);
|
|
117
|
+
}
|
|
118
|
+
const descriptor = {
|
|
119
|
+
station: 1,
|
|
120
|
+
name, slug,
|
|
121
|
+
envtoken: envtoken(slug),
|
|
122
|
+
version, target,
|
|
123
|
+
base: String(options.base || ''),
|
|
124
|
+
server, auth, entities, features,
|
|
125
|
+
};
|
|
126
|
+
return { descriptor, warnings };
|
|
127
|
+
}
|
|
128
|
+
// Canonical serialization (design §4): UTF-8, object keys sorted
|
|
129
|
+
// bytewise, no insignificant whitespace, minimal JSON escaping. The
|
|
130
|
+
// proxy dedupes registrations by a hash of this, so every language must
|
|
131
|
+
// produce identical bytes - the `canonical-serialize` corpus section
|
|
132
|
+
// carries the adversarial cases.
|
|
133
|
+
//
|
|
134
|
+
// The bytewise sort compares UTF-8 BYTE SEQUENCES, not UTF-16 code
|
|
135
|
+
// units, through TextEncoder rather than Buffer: TextEncoder is a
|
|
136
|
+
// standard global in Node and every browser, so this module stays on
|
|
137
|
+
// the browser entry's import graph (§2.2, §17 Phase 1) with no node:
|
|
138
|
+
// dependency. Uint8Array elements are unsigned bytes, so plain numeric
|
|
139
|
+
// comparison IS the bytewise order Buffer.compare gave - the corpus'
|
|
140
|
+
// non-ASCII sort case pins the equivalence.
|
|
141
|
+
const UTF8 = new TextEncoder();
|
|
142
|
+
function bytecompare(a, b) {
|
|
143
|
+
const ab = UTF8.encode(a), bb = UTF8.encode(b);
|
|
144
|
+
const n = ab.length < bb.length ? ab.length : bb.length;
|
|
145
|
+
for (let i = 0; i < n; i++) {
|
|
146
|
+
if (ab[i] !== bb[i]) {
|
|
147
|
+
return ab[i] - bb[i];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return ab.length - bb.length;
|
|
151
|
+
}
|
|
152
|
+
function canonicalSerialize(value) {
|
|
153
|
+
if (null === value || 'boolean' === typeof value || 'number' === typeof value) {
|
|
154
|
+
return JSON.stringify(value);
|
|
155
|
+
}
|
|
156
|
+
if ('string' === typeof value) {
|
|
157
|
+
return JSON.stringify(value);
|
|
158
|
+
}
|
|
159
|
+
if (Array.isArray(value)) {
|
|
160
|
+
return '[' + value.map(canonicalSerialize).join(',') + ']';
|
|
161
|
+
}
|
|
162
|
+
if ('object' === typeof value) {
|
|
163
|
+
const keys = Object.keys(value).filter((k) => undefined !== value[k]);
|
|
164
|
+
// Bytewise sort: compare UTF-8 byte sequences, not UTF-16 code units.
|
|
165
|
+
keys.sort(bytecompare);
|
|
166
|
+
return '{' + keys.map((k) => JSON.stringify(k) + ':' + canonicalSerialize(value[k])).join(',') + '}';
|
|
167
|
+
}
|
|
168
|
+
return 'null';
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=descriptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"descriptor.js","sourceRoot":"","sources":["../../src/descriptor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare const CODES: readonly ["station_no_proxy", "station_secret_no_value", "station_secret_error", "station_secret_name", "station_host_allow", "station_grant_expired", "station_wrap_order", "station_protocol", "station_no_plugin", "station_no_entity", "station_no_op", "station_agent_allow", "station_body_limit", "station_replay_lossy", "station_open_conflict", "station_bound_twice", "station_config_invalid", "station_config_secret", "station_secret_collision", "station_feature_reserved", "station_instance_api", "station_no_instance", "station_instance_inactive", "station_sdk_load", "station_no_factory", "station_factory_conflict", "station_feature_unknown", "station_feature_option", "station_feature_order"];
|
|
2
|
+
export type StationErrorCode = typeof CODES[number];
|
|
3
|
+
export declare class StationError extends Error {
|
|
4
|
+
code: StationErrorCode;
|
|
5
|
+
constructor(code: StationErrorCode, message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare function isKnownCode(code: string): boolean;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Error codes follow the SDKs' house grammar (design §14):
|
|
3
|
+
// <subject>_<condition>, absence as no_<thing>, gates as _allow.
|
|
4
|
+
// The `errors` corpus section pins the exact strings.
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.StationError = void 0;
|
|
7
|
+
exports.isKnownCode = isKnownCode;
|
|
8
|
+
const CODES = [
|
|
9
|
+
'station_no_proxy',
|
|
10
|
+
'station_secret_no_value',
|
|
11
|
+
'station_secret_error',
|
|
12
|
+
'station_secret_name',
|
|
13
|
+
'station_host_allow',
|
|
14
|
+
'station_grant_expired',
|
|
15
|
+
'station_wrap_order',
|
|
16
|
+
'station_protocol',
|
|
17
|
+
'station_no_plugin',
|
|
18
|
+
'station_no_entity',
|
|
19
|
+
'station_no_op',
|
|
20
|
+
'station_agent_allow',
|
|
21
|
+
'station_body_limit',
|
|
22
|
+
'station_replay_lossy',
|
|
23
|
+
'station_open_conflict',
|
|
24
|
+
'station_bound_twice',
|
|
25
|
+
// Declarative config (station-declarative-config.md §6.4). Stage 1
|
|
26
|
+
// raises the first three; `station_feature_reserved` is the pure-data
|
|
27
|
+
// half of §8.4/§8.6, checkable before feature.ts exists because both
|
|
28
|
+
// rules are lexical - a `station` key in a feature map, a `feature`
|
|
29
|
+
// key inside `options`.
|
|
30
|
+
'station_config_invalid',
|
|
31
|
+
'station_config_secret',
|
|
32
|
+
'station_secret_collision',
|
|
33
|
+
'station_feature_reserved',
|
|
34
|
+
// Instances (design §6.4). `as` is a tag, not a free name: a full ref
|
|
35
|
+
// whose name is not the SDK's api slug is this.
|
|
36
|
+
'station_instance_api',
|
|
37
|
+
'station_no_instance',
|
|
38
|
+
'station_instance_inactive',
|
|
39
|
+
'station_sdk_load',
|
|
40
|
+
'station_no_factory',
|
|
41
|
+
'station_factory_conflict',
|
|
42
|
+
// Features (design §8.4, §8.5). The checker is derived from the SDK's
|
|
43
|
+
// own declaration, so a feature typo is a CI failure rather than a
|
|
44
|
+
// setting that quietly did nothing in production.
|
|
45
|
+
'station_feature_unknown',
|
|
46
|
+
'station_feature_option',
|
|
47
|
+
'station_feature_order',
|
|
48
|
+
];
|
|
49
|
+
class StationError extends Error {
|
|
50
|
+
constructor(code, message) {
|
|
51
|
+
super(code + ': ' + message);
|
|
52
|
+
this.name = 'StationError';
|
|
53
|
+
this.code = code;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.StationError = StationError;
|
|
57
|
+
function isKnownCode(code) {
|
|
58
|
+
return CODES.includes(code);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/error.ts"],"names":[],"mappings":";AAAA,2DAA2D;AAC3D,iEAAiE;AACjE,sDAAsD;;;AA2DtD,kCAEC;AA3DD,MAAM,KAAK,GAAG;IACZ,kBAAkB;IAClB,yBAAyB;IACzB,sBAAsB;IACtB,qBAAqB;IACrB,oBAAoB;IACpB,uBAAuB;IACvB,oBAAoB;IACpB,kBAAkB;IAClB,mBAAmB;IACnB,mBAAmB;IACnB,eAAe;IACf,qBAAqB;IACrB,oBAAoB;IACpB,sBAAsB;IACtB,uBAAuB;IACvB,qBAAqB;IAErB,mEAAmE;IACnE,sEAAsE;IACtE,qEAAqE;IACrE,oEAAoE;IACpE,wBAAwB;IACxB,wBAAwB;IACxB,uBAAuB;IACvB,0BAA0B;IAC1B,0BAA0B;IAE1B,sEAAsE;IACtE,gDAAgD;IAChD,sBAAsB;IACtB,qBAAqB;IACrB,2BAA2B;IAC3B,kBAAkB;IAClB,oBAAoB;IACpB,0BAA0B;IAE1B,sEAAsE;IACtE,mEAAmE;IACnE,kDAAkD;IAClD,yBAAyB;IACzB,wBAAwB;IACxB,uBAAuB;CACf,CAAA;AAIV,MAAa,YAAa,SAAQ,KAAK;IAGrC,YAAY,IAAsB,EAAE,OAAe;QACjD,KAAK,CAAC,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,CAAA;QAC5B,IAAI,CAAC,IAAI,GAAG,cAAc,CAAA;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;CACF;AARD,oCAQC;AAED,SAAgB,WAAW,CAAC,IAAY;IACtC,OAAQ,KAA2B,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;AACpD,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { StationEvent } from './types';
|
|
2
|
+
export declare class EventBuffer {
|
|
3
|
+
private ring;
|
|
4
|
+
private max;
|
|
5
|
+
private drops;
|
|
6
|
+
private taps;
|
|
7
|
+
constructor(max?: number);
|
|
8
|
+
emit(ev: StationEvent): void;
|
|
9
|
+
events(): StationEvent[];
|
|
10
|
+
tap(fn: (ev: StationEvent) => void): () => void;
|
|
11
|
+
status(): {
|
|
12
|
+
buffered: number;
|
|
13
|
+
dropped: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventBuffer = void 0;
|
|
4
|
+
// The solo event surface (design §6): a bounded ring buffer plus a live
|
|
5
|
+
// tap with serialized callbacks. Events never fail an operation; overflow
|
|
6
|
+
// drops oldest and the drop count is visible in status().
|
|
7
|
+
class EventBuffer {
|
|
8
|
+
constructor(max) {
|
|
9
|
+
this.ring = [];
|
|
10
|
+
this.drops = 0;
|
|
11
|
+
this.taps = [];
|
|
12
|
+
this.max = null == max ? 1000 : max;
|
|
13
|
+
}
|
|
14
|
+
emit(ev) {
|
|
15
|
+
this.ring.push(ev);
|
|
16
|
+
if (this.ring.length > this.max) {
|
|
17
|
+
this.ring.shift();
|
|
18
|
+
this.drops++;
|
|
19
|
+
}
|
|
20
|
+
// Serialized, and a throwing tap must not fail the operation that
|
|
21
|
+
// emitted the event.
|
|
22
|
+
for (const fn of this.taps) {
|
|
23
|
+
try {
|
|
24
|
+
fn(ev);
|
|
25
|
+
}
|
|
26
|
+
catch (_e) { }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
events() {
|
|
30
|
+
return this.ring.slice();
|
|
31
|
+
}
|
|
32
|
+
tap(fn) {
|
|
33
|
+
this.taps.push(fn);
|
|
34
|
+
return () => {
|
|
35
|
+
const i = this.taps.indexOf(fn);
|
|
36
|
+
if (-1 !== i) {
|
|
37
|
+
this.taps.splice(i, 1);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
status() {
|
|
42
|
+
return { buffered: this.ring.length, dropped: this.drops };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.EventBuffer = EventBuffer;
|
|
46
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/events.ts"],"names":[],"mappings":";;;AAEA,wEAAwE;AACxE,0EAA0E;AAC1E,0DAA0D;AAE1D,MAAa,WAAW;IAMtB,YAAY,GAAY;QALhB,SAAI,GAAmB,EAAE,CAAA;QAEzB,UAAK,GAAG,CAAC,CAAA;QACT,SAAI,GAAmC,EAAE,CAAA;QAG/C,IAAI,CAAC,GAAG,GAAG,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAA;IACrC,CAAC;IAED,IAAI,CAAC,EAAgB;QACnB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAClB,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAA;YACjB,IAAI,CAAC,KAAK,EAAE,CAAA;QACd,CAAC;QACD,kEAAkE;QAClE,qBAAqB;QACrB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC;gBAAC,EAAE,CAAC,EAAE,CAAC,CAAA;YAAC,CAAC;YAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAA;IAC1B,CAAC;IAED,GAAG,CAAC,EAA8B;QAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAClB,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAC/B,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YAAC,CAAC;QAC1C,CAAC,CAAA;IACH,CAAC;IAED,MAAM;QACJ,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,CAAA;IAC5D,CAAC;CACF;AAtCD,kCAsCC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type Factory = {
|
|
2
|
+
construct: (options: any) => any;
|
|
3
|
+
config: any;
|
|
4
|
+
};
|
|
5
|
+
export type FactoryEntry = {
|
|
6
|
+
api: string;
|
|
7
|
+
construct: (options: any) => any;
|
|
8
|
+
config: any;
|
|
9
|
+
descriptor: any;
|
|
10
|
+
warnings: string[];
|
|
11
|
+
};
|
|
12
|
+
/** Register an api's `{construct, config}` pair.
|
|
13
|
+
*
|
|
14
|
+
* Idempotent per api: registering the SAME pair twice is a no-op,
|
|
15
|
+
* because module self-registration and an explicit `provide` for one
|
|
16
|
+
* api is an ordinary thing for an application to end up with. A second
|
|
17
|
+
* registration with a DIFFERENT factory is `station_factory_conflict` —
|
|
18
|
+
* silently picking one of two SDK builds is not a thing to do quietly. */
|
|
19
|
+
export declare function provide(api: string, factory: Factory): FactoryEntry;
|
|
20
|
+
export declare function factoryFor(api: string): FactoryEntry | undefined;
|
|
21
|
+
export declare function provided(): string[];
|
|
22
|
+
/** Test seam. The table is process-global by design, so a suite that
|
|
23
|
+
* registers factories has to be able to put the process back. */
|
|
24
|
+
export declare function resetFactories(): void;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* The factory table (design §6.2).
|
|
3
|
+
*
|
|
4
|
+
* A FACTORY IS A CONSTRUCTOR *PLUS* THE SDK'S STATIC CONFIG, not a bare
|
|
5
|
+
* function, and leaving the second half out was a hole in the first
|
|
6
|
+
* draft of §6.2.
|
|
7
|
+
*
|
|
8
|
+
* Station composes the ordered feature array FOR the constructor, so it
|
|
9
|
+
* needs the transport roles and the feature option schemas BEFORE
|
|
10
|
+
* construction — but §7.5 has the adapter build and register its
|
|
11
|
+
* descriptor DURING construction. Nothing would be known in time.
|
|
12
|
+
*
|
|
13
|
+
* The config is available, though: `configDefinition` emits it as a
|
|
14
|
+
* module-level constant in the generated package, so it exists as soon
|
|
15
|
+
* as the package is linked and long before any instance is built.
|
|
16
|
+
* Station normalizes the descriptor AT PROVIDE TIME, and three things
|
|
17
|
+
* follow:
|
|
18
|
+
*
|
|
19
|
+
* - §7.4's per-api descriptor cache is populated at registration
|
|
20
|
+
* rather than on first construction;
|
|
21
|
+
* - `check()` can validate every instance's feature config WITHOUT
|
|
22
|
+
* constructing anything;
|
|
23
|
+
* - the adapter's registration during construction becomes a
|
|
24
|
+
* reconciliation — same descriptor, now bound to a live client —
|
|
25
|
+
* rather than the first sighting.
|
|
26
|
+
*
|
|
27
|
+
* The table is PROCESS-GLOBAL because path 1 of §6.2 is module
|
|
28
|
+
* self-registration: a generated package registers itself when it is
|
|
29
|
+
* linked, which happens once per process and not once per Station. */
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.provide = provide;
|
|
32
|
+
exports.factoryFor = factoryFor;
|
|
33
|
+
exports.provided = provided;
|
|
34
|
+
exports.resetFactories = resetFactories;
|
|
35
|
+
const error_1 = require("./error");
|
|
36
|
+
const descriptor_1 = require("./descriptor");
|
|
37
|
+
const TABLE = new Map();
|
|
38
|
+
/** Register an api's `{construct, config}` pair.
|
|
39
|
+
*
|
|
40
|
+
* Idempotent per api: registering the SAME pair twice is a no-op,
|
|
41
|
+
* because module self-registration and an explicit `provide` for one
|
|
42
|
+
* api is an ordinary thing for an application to end up with. A second
|
|
43
|
+
* registration with a DIFFERENT factory is `station_factory_conflict` —
|
|
44
|
+
* silently picking one of two SDK builds is not a thing to do quietly. */
|
|
45
|
+
function provide(api, factory) {
|
|
46
|
+
const slug = String(api);
|
|
47
|
+
const prior = TABLE.get(slug);
|
|
48
|
+
if (null != prior) {
|
|
49
|
+
if (prior.construct === factory.construct && prior.config === factory.config) {
|
|
50
|
+
return prior;
|
|
51
|
+
}
|
|
52
|
+
throw new error_1.StationError('station_factory_conflict', 'two different factories registered for api "' + slug + '"; a ' +
|
|
53
|
+
'process has one build of an SDK, and picking between two ' +
|
|
54
|
+
'silently is not a thing to do quietly');
|
|
55
|
+
}
|
|
56
|
+
// AT PROVIDE TIME, which is the whole point of carrying `config`.
|
|
57
|
+
const { descriptor, warnings } = (0, descriptor_1.normalizeDescriptor)(factory.config, undefined);
|
|
58
|
+
const entry = {
|
|
59
|
+
api: slug,
|
|
60
|
+
construct: factory.construct,
|
|
61
|
+
config: factory.config,
|
|
62
|
+
descriptor,
|
|
63
|
+
warnings,
|
|
64
|
+
};
|
|
65
|
+
TABLE.set(slug, entry);
|
|
66
|
+
return entry;
|
|
67
|
+
}
|
|
68
|
+
function factoryFor(api) {
|
|
69
|
+
return TABLE.get(String(api));
|
|
70
|
+
}
|
|
71
|
+
function provided() {
|
|
72
|
+
return Array.from(TABLE.keys()).sort();
|
|
73
|
+
}
|
|
74
|
+
/** Test seam. The table is process-global by design, so a suite that
|
|
75
|
+
* registers factories has to be able to put the process back. */
|
|
76
|
+
function resetFactories() {
|
|
77
|
+
TABLE.clear();
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/factory.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;sEA2BsE;;AA2BtE,0BAwBC;AAED,gCAEC;AAED,4BAEC;AAID,wCAEC;AA/DD,mCAAsC;AACtC,6CAAkD;AAelD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAwB,CAAA;AAE7C;;;;;;0EAM0E;AAC1E,SAAgB,OAAO,CAAC,GAAW,EAAE,OAAgB;IACnD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;IACxB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7B,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;QAClB,IAAI,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;YAC7E,OAAO,KAAK,CAAA;QACd,CAAC;QACD,MAAM,IAAI,oBAAY,CAAC,0BAA0B,EAC/C,8CAA8C,GAAG,IAAI,GAAG,OAAO;YAC/D,2DAA2D;YAC3D,uCAAuC,CAAC,CAAA;IAC5C,CAAC;IAED,kEAAkE;IAClE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAA,gCAAmB,EAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC/E,MAAM,KAAK,GAAiB;QAC1B,GAAG,EAAE,IAAI;QACT,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,UAAU;QACV,QAAQ;KACT,CAAA;IACD,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACtB,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAgB,UAAU,CAAC,GAAW;IACpC,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAC/B,CAAC;AAED,SAAgB,QAAQ;IACtB,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;AACxC,CAAC;AAED;iEACiE;AACjE,SAAgB,cAAc;IAC5B,KAAK,CAAC,KAAK,EAAE,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/** Reserved on a feature entry: not options, and never passed through
|
|
2
|
+
* to the SDK's own option map. */
|
|
3
|
+
export declare const RESERVED_KEYS: string[];
|
|
4
|
+
/** The six sources, in §3.3's order extended by the profile level:
|
|
5
|
+
*
|
|
6
|
+
* 1 base.feature 4 overlay.feature
|
|
7
|
+
* 2 base.api[<api>].feature 5 overlay.api[<api>].feature
|
|
8
|
+
* 3 base.sdk[<ref>].feature 6 overlay.sdk[<ref>].feature
|
|
9
|
+
*
|
|
10
|
+
* PROFILE SPECIFICITY OUTRANKS BLOCK SPECIFICITY, and within a profile
|
|
11
|
+
* the narrower block wins — the same principle as §3.3, one level down.
|
|
12
|
+
*
|
|
13
|
+
* `feature` is the ONE key where §3.3's shallow-per-key rule is wrong:
|
|
14
|
+
* composition is the entire point, a fleet default plus a per-instance
|
|
15
|
+
* tweak. So it is a TWO-LEVEL merge — per feature name, then per option
|
|
16
|
+
* key — and no deeper. A map-valued option REPLACES wholesale, which is
|
|
17
|
+
* what `{"$MERGE": {"deep": 2}}` states and what a port defaulting to a
|
|
18
|
+
* deep merge would silently get wrong.
|
|
19
|
+
*
|
|
20
|
+
* Same defaults-after-merge rule as §3.3, one level down: an entry
|
|
21
|
+
* mentioned at one level with only a tuning key must NOT synthesize
|
|
22
|
+
* `active` and switch on a feature a broader level turned off. That is
|
|
23
|
+
* the §3.3 defect one level down, and it is why the caller passes RAW
|
|
24
|
+
* blocks here. */
|
|
25
|
+
export declare function mergefeatures(sources: any[]): {
|
|
26
|
+
[name: string]: any;
|
|
27
|
+
};
|
|
28
|
+
/** The six sources for one instance, in order. Assembled here rather
|
|
29
|
+
* than at the call site so the order lives in exactly one place. */
|
|
30
|
+
export declare function featuresources(base: any, overlay: any, api: string, ref: string): any[];
|
|
31
|
+
/** `test` substitutes the base transport, so it takes the innermost
|
|
32
|
+
* band; `station` sits immediately outside it, pinned; everything else
|
|
33
|
+
* is band 0, outside station.
|
|
34
|
+
*
|
|
35
|
+
* THE DEFAULT IS TODAY'S BEHAVIOUR EXPRESSED IN THE NEW MODEL rather
|
|
36
|
+
* than as a special case: a project that writes no `order` anywhere
|
|
37
|
+
* sees exactly today's nesting, and sdkgen's two `makeOptions` special
|
|
38
|
+
* cases become two band values rather than two branches. */
|
|
39
|
+
export declare const BAND_DEFAULT = 0;
|
|
40
|
+
export declare const BAND_STATION = 100;
|
|
41
|
+
export declare const BAND_TEST = 200;
|
|
42
|
+
/** Higher is further IN. */
|
|
43
|
+
export declare function defaultband(name: string): number;
|
|
44
|
+
export type Ordered = {
|
|
45
|
+
name: string;
|
|
46
|
+
band: number;
|
|
47
|
+
entry: any;
|
|
48
|
+
};
|
|
49
|
+
/** Resolve the activation order: constraints, then bands, then the
|
|
50
|
+
* feature's position in the merged map.
|
|
51
|
+
*
|
|
52
|
+
* `before`/`after` take a feature name or a list of them and are
|
|
53
|
+
* SATISFIED VACUOUSLY when the named feature is absent — `after: 'test'`
|
|
54
|
+
* loads fine in a project with no test feature, which is sdkgen's
|
|
55
|
+
* `__after__` behaviour kept rather than reinvented.
|
|
56
|
+
*
|
|
57
|
+
* Constraints beat bands; bands break ties no constraint decides;
|
|
58
|
+
* remaining ties break by declaration position, so the result is a
|
|
59
|
+
* stable topological sort with no alphabetical accident in it.
|
|
60
|
+
*
|
|
61
|
+
* Returns OUTERMOST FIRST, which is the array form the constructor
|
|
62
|
+
* takes and the direction plugin's chain composes in. */
|
|
63
|
+
export declare function resolveorder(merged: {
|
|
64
|
+
[name: string]: any;
|
|
65
|
+
}): Ordered[];
|
|
66
|
+
/** Station's own position is PINNED and not orderable (§8.4): an order
|
|
67
|
+
* that moves `station` away from immediately-outside-the-base is
|
|
68
|
+
* REJECTED, not honoured.
|
|
69
|
+
*
|
|
70
|
+
* The pin is `innermost`, and the spelling matters. A chain composes
|
|
71
|
+
* with the FIRST binding outermost, so a pin written in sort terms —
|
|
72
|
+
* "station first" — would place every other wrapper between the adapter
|
|
73
|
+
* and the base: the exact inversion of the invariant, and one that
|
|
74
|
+
* would leave station's wire-truth events observing the wrong boundary
|
|
75
|
+
* while still looking ordered. */
|
|
76
|
+
export declare function checkpin(ordered: Ordered[]): void;
|
|
77
|
+
export type FeatureFault = {
|
|
78
|
+
code: string;
|
|
79
|
+
feature: string;
|
|
80
|
+
key?: string;
|
|
81
|
+
message: string;
|
|
82
|
+
};
|
|
83
|
+
/** Check a merged feature map against the SDK'S OWN DECLARATION.
|
|
84
|
+
*
|
|
85
|
+
* The schema arrives with the FACTORY rather than with a live client
|
|
86
|
+
* (§6.2), so this needs no construction and no network — which is what
|
|
87
|
+
* lets `check()` run it for every instance in CI.
|
|
88
|
+
*
|
|
89
|
+
* Derived from the descriptor, never hand-written, so it cannot drift:
|
|
90
|
+
* when a feature gains an option, the next regeneration teaches station
|
|
91
|
+
* about it with no station change.
|
|
92
|
+
*
|
|
93
|
+
* SCALARS AGREE BY CONSTRUCTION; COMPOUND OPTIONS ARE KIND-CHECKED, and
|
|
94
|
+
* that limit is real. An empty list default says nothing reliable about
|
|
95
|
+
* its element type and a nested map default says nothing about its
|
|
96
|
+
* value shapes, so `methods: [{}]` against a `['GET']` default is
|
|
97
|
+
* caught while `noProxy: []` accepts anything list-shaped. Closing that
|
|
98
|
+
* needs the feature model to declare an explicit option schema rather
|
|
99
|
+
* than only a default. */
|
|
100
|
+
export declare function checkfeatures(merged: {
|
|
101
|
+
[name: string]: any;
|
|
102
|
+
}, descriptor: any): FeatureFault[];
|
|
103
|
+
/** Compose the merged map into the ORDERED ARRAY FORM the constructor
|
|
104
|
+
* takes. No new seam: it is what `connect()` already does for station's
|
|
105
|
+
* own placement, with more in it. */
|
|
106
|
+
export declare function composefeatures(ordered: Ordered[]): any[];
|