@stealthscale/sdk-host 0.1.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/LICENSE +21 -0
- package/README.md +257 -0
- package/dist/create-routes-CkgZV-dU.js +4730 -0
- package/dist/cyclonedx/bom.json +1 -0
- package/dist/index.d.ts +288 -0
- package/dist/index.js +81 -0
- package/dist/openfeature.d.ts +27 -0
- package/dist/openfeature.js +80 -0
- package/dist/page-7ScZC_LI.js +62 -0
- package/dist/section-CtcVFcBK.js +41 -0
- package/dist/standalone/app.d.ts +65 -0
- package/dist/standalone/app.js +1426 -0
- package/dist/standalone-XfUZYt9b.d.ts +137 -0
- package/dist/standalone.d.ts +2 -0
- package/dist/standalone.js +257 -0
- package/dist/words-yI-WdYM3.js +58 -0
- package/locales/en/host.json +135 -0
- package/package.json +139 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { AccessCheck, AccessSource, AnyContract, FlagSource, InstalledOptions, PluginManifest, ProductDefinition, ResolvedProduct, Session, SessionSource } from "@stealthscale/sdk-core";
|
|
2
|
+
//#region src/standalone.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Lists the plugin a standalone product runs, and the plugins installed beside it.
|
|
5
|
+
*/
|
|
6
|
+
interface StandaloneOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Contracts of the plugins installed beside the plugin, each from its contract alone. None where
|
|
9
|
+
* left out.
|
|
10
|
+
*/
|
|
11
|
+
readonly beside?: readonly AnyContract[] | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* The plugin's configuration, as its schema admits it. The schema's defaults where left out.
|
|
14
|
+
*/
|
|
15
|
+
readonly config?: InstalledOptions["config"];
|
|
16
|
+
/**
|
|
17
|
+
* The plugin's contract.
|
|
18
|
+
*/
|
|
19
|
+
readonly contract: AnyContract;
|
|
20
|
+
/**
|
|
21
|
+
* The plugin's manifest. The plugin is installed from its contract alone where left out.
|
|
22
|
+
*/
|
|
23
|
+
readonly manifest?: PluginManifest | undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Describes a module a standalone product is built from: a plugin's manifest module, or a contract
|
|
27
|
+
* package beside it.
|
|
28
|
+
*/
|
|
29
|
+
interface StandaloneModule {
|
|
30
|
+
/**
|
|
31
|
+
* Where the module comes from: a path or a package name, which an error names.
|
|
32
|
+
*/
|
|
33
|
+
readonly from: string;
|
|
34
|
+
/**
|
|
35
|
+
* The module's exports.
|
|
36
|
+
*/
|
|
37
|
+
readonly module: Readonly<Record<string, unknown>>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Describes the session source of a standalone product, whose session a panel or a test replaces.
|
|
41
|
+
*/
|
|
42
|
+
interface StandaloneSession extends SessionSource {
|
|
43
|
+
/**
|
|
44
|
+
* Replaces the session, and calls every listener where the session is another object.
|
|
45
|
+
*/
|
|
46
|
+
readonly set: (session: Session) => void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Decides one check on one resource: true where the person has the permission on it.
|
|
50
|
+
*/
|
|
51
|
+
type Decider = (check: AccessCheck) => boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Describes the access source of a standalone product, whose decisions a panel or a test switches.
|
|
54
|
+
*
|
|
55
|
+
* @remarks
|
|
56
|
+
* The source denies a check whose permission the session lacks, whatever the decision, as an
|
|
57
|
+
* access service decides for the person the session names.
|
|
58
|
+
*/
|
|
59
|
+
interface StandaloneAccess extends AccessSource {
|
|
60
|
+
/**
|
|
61
|
+
* Allows every check the session's permissions admit from now on.
|
|
62
|
+
*/
|
|
63
|
+
readonly allow: () => void;
|
|
64
|
+
/**
|
|
65
|
+
* Decides every check the session's permissions admit from now on with the function.
|
|
66
|
+
*/
|
|
67
|
+
readonly decide: (decider: Decider) => void;
|
|
68
|
+
/**
|
|
69
|
+
* Denies every check from now on.
|
|
70
|
+
*/
|
|
71
|
+
readonly deny: () => void;
|
|
72
|
+
/**
|
|
73
|
+
* Leaves every check from now on pending.
|
|
74
|
+
*/
|
|
75
|
+
readonly pending: () => void;
|
|
76
|
+
/**
|
|
77
|
+
* Calls the listener after the decision or the session changes, so the host asks again. Returns a
|
|
78
|
+
* function that stops the calls.
|
|
79
|
+
*/
|
|
80
|
+
readonly subscribe: (listener: () => void) => () => void;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Lists the sources the host of a standalone product reads.
|
|
84
|
+
*/
|
|
85
|
+
interface StandaloneSources {
|
|
86
|
+
/**
|
|
87
|
+
* Decides every check on one resource, allowing each the session's permissions admit until a
|
|
88
|
+
* panel or a test switches the decision.
|
|
89
|
+
*/
|
|
90
|
+
readonly access: StandaloneAccess;
|
|
91
|
+
/**
|
|
92
|
+
* Turns every boolean flag on, and leaves every experiment at its default.
|
|
93
|
+
*/
|
|
94
|
+
readonly flags: FlagSource;
|
|
95
|
+
/**
|
|
96
|
+
* Returns the session a panel or a test last set.
|
|
97
|
+
*/
|
|
98
|
+
readonly session: StandaloneSession;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Returns the definition of a product that runs one plugin: the plugin from its manifest, and each
|
|
102
|
+
* plugin beside it from its contract alone.
|
|
103
|
+
*
|
|
104
|
+
* @remarks
|
|
105
|
+
* A route of a plugin installed from its contract alone renders a page that names the route and
|
|
106
|
+
* renders each of the plugin's slots with its sample props. Such a plugin's extensions render the
|
|
107
|
+
* content they wrap, or nothing, and its commands resolve with nothing. Its settings sections
|
|
108
|
+
* without a schema name their plugin. The product's id is the plugin's, and its name is the key
|
|
109
|
+
* `plugin.name`, so the product's name is the plugin's own.
|
|
110
|
+
* @param options - The plugin's contract and manifest, its configuration, and the contracts beside
|
|
111
|
+
* it.
|
|
112
|
+
* @throws {@link Error} Where the manifest implements another contract.
|
|
113
|
+
*/
|
|
114
|
+
declare function standaloneProduct(options: StandaloneOptions): ProductDefinition;
|
|
115
|
+
/**
|
|
116
|
+
* Returns the definition of a product that runs one plugin, from the plugin's manifest module and
|
|
117
|
+
* the module of each contract package beside it.
|
|
118
|
+
*
|
|
119
|
+
* @remarks
|
|
120
|
+
* The standalone layer of `vite-config-product` writes a definition that calls this with the
|
|
121
|
+
* modules it imports, so an author states package names and paths alone.
|
|
122
|
+
* @param plugin - The module that exports the plugin's manifest.
|
|
123
|
+
* @param beside - The module of each contract package installed beside the plugin.
|
|
124
|
+
* @throws {@link Error} Where a module exports no manifest or contract, or several, naming the
|
|
125
|
+
* module.
|
|
126
|
+
*/
|
|
127
|
+
declare function standaloneFrom(plugin: StandaloneModule, beside?: readonly StandaloneModule[]): ProductDefinition;
|
|
128
|
+
/**
|
|
129
|
+
* Returns the sources of a standalone product's host: a signed-in session with every permission and
|
|
130
|
+
* entitlement the product declares, every check on one resource the session's permissions admit
|
|
131
|
+
* allowed, every boolean flag on and every experiment at its default.
|
|
132
|
+
*
|
|
133
|
+
* @param product - The permissions and entitlements the installed plugins declare.
|
|
134
|
+
*/
|
|
135
|
+
declare function standaloneSources(product: Pick<ResolvedProduct, "entitlements" | "permissions">): StandaloneSources;
|
|
136
|
+
//#endregion
|
|
137
|
+
export { StandaloneSession as a, standaloneProduct as c, StandaloneOptions as i, standaloneSources as l, StandaloneAccess as n, StandaloneSources as o, StandaloneModule as r, standaloneFrom as s, Decider as t };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as StandaloneSession, c as standaloneProduct, i as StandaloneOptions, l as standaloneSources, n as StandaloneAccess, o as StandaloneSources, r as StandaloneModule, s as standaloneFrom, t as Decider } from "./standalone-XfUZYt9b.js";
|
|
2
|
+
export { Decider, StandaloneAccess, StandaloneModule, StandaloneOptions, StandaloneSession, StandaloneSources, standaloneFrom, standaloneProduct, standaloneSources };
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { API_RANGE } from "@stealthscale/sdk-core";
|
|
2
|
+
//#region src/standalone.ts
|
|
3
|
+
/**
|
|
4
|
+
* Builds the product a plugin runs in alone, for its tests and its standalone page: the plugin, the
|
|
5
|
+
* plugins beside it installed from their contracts alone, and the sources of a signed-in session.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* The module imports `sdk-core` alone. The build evaluates a product's definition in Node without
|
|
9
|
+
* a CommonJS loader, and an inline type import still loads its package there.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Allows every check.
|
|
13
|
+
*/
|
|
14
|
+
function allowed() {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Denies every check.
|
|
19
|
+
*/
|
|
20
|
+
function denied() {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The version a standalone product states, which no deployment compares.
|
|
25
|
+
*/
|
|
26
|
+
const VERSION = "0.0.0";
|
|
27
|
+
/**
|
|
28
|
+
* Does nothing: the run of a command without code, and the end of a subscription to a source that
|
|
29
|
+
* never notifies.
|
|
30
|
+
*/
|
|
31
|
+
function nothing() {}
|
|
32
|
+
/**
|
|
33
|
+
* Renders the content a wrapping extension wraps, and nothing in any other position.
|
|
34
|
+
*/
|
|
35
|
+
function PlaceholderExtension({ children }) {
|
|
36
|
+
return children;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The code of every command of a plugin installed from its contract alone.
|
|
40
|
+
*/
|
|
41
|
+
const COMMAND = { run: () => Promise.resolve({ nothing }) };
|
|
42
|
+
/**
|
|
43
|
+
* The code of every extension of a plugin installed from its contract alone.
|
|
44
|
+
*/
|
|
45
|
+
const EXTENSION = { component: () => Promise.resolve({ PlaceholderExtension }) };
|
|
46
|
+
/**
|
|
47
|
+
* The code of every settings section without a schema of a plugin installed from its contract
|
|
48
|
+
* alone.
|
|
49
|
+
*/
|
|
50
|
+
const SECTION = { component: () => import("./section-CtcVFcBK.js") };
|
|
51
|
+
/**
|
|
52
|
+
* The flag source of a standalone product: every boolean flag on, and every experiment at the value
|
|
53
|
+
* the product or the contract states.
|
|
54
|
+
*/
|
|
55
|
+
const FLAGS = {
|
|
56
|
+
evaluate: ({ type }) => type === "boolean" ? true : void 0,
|
|
57
|
+
subscribe: () => nothing
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* A batch of decisions that never settles.
|
|
61
|
+
*/
|
|
62
|
+
const PENDING = new Promise(nothing);
|
|
63
|
+
/**
|
|
64
|
+
* Returns a value and its listeners, which each replacement with another value calls.
|
|
65
|
+
*
|
|
66
|
+
* @param initial - The value before the first replacement.
|
|
67
|
+
*/
|
|
68
|
+
function kept(initial) {
|
|
69
|
+
let value = initial;
|
|
70
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
71
|
+
return {
|
|
72
|
+
get: () => value,
|
|
73
|
+
set: (next) => {
|
|
74
|
+
if (Object.is(next, value)) return;
|
|
75
|
+
value = next;
|
|
76
|
+
for (const listener of [...listeners]) listener();
|
|
77
|
+
},
|
|
78
|
+
subscribe: (listener) => {
|
|
79
|
+
listeners.add(listener);
|
|
80
|
+
return () => {
|
|
81
|
+
listeners.delete(listener);
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Returns the importer of the placeholder page of one route.
|
|
88
|
+
*
|
|
89
|
+
* @param routeId - Qualified id of the route the page names.
|
|
90
|
+
* @param contract - The contract whose slots the page renders.
|
|
91
|
+
*/
|
|
92
|
+
function pageOf(routeId, contract) {
|
|
93
|
+
return async () => {
|
|
94
|
+
const { placeholderPageOf } = await import("./page-7ScZC_LI.js");
|
|
95
|
+
return { PlaceholderPage: placeholderPageOf(routeId, contract) };
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Returns a record with each value mapped, under the same names.
|
|
100
|
+
*/
|
|
101
|
+
function mapped(record, map) {
|
|
102
|
+
return Object.fromEntries(Object.entries(record).map(([name, value]) => [name, map(value)]));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Returns the manifest of a plugin installed from its contract alone: a placeholder for every name
|
|
106
|
+
* that needs code.
|
|
107
|
+
*/
|
|
108
|
+
function placeholderOf(contract) {
|
|
109
|
+
const sections = Object.entries(contract.settings.sections).filter(([, section]) => section.schema === void 0);
|
|
110
|
+
return {
|
|
111
|
+
apiVersion: API_RANGE,
|
|
112
|
+
code: {
|
|
113
|
+
commands: mapped(contract.commands, () => COMMAND),
|
|
114
|
+
extensions: mapped(contract.extensions, () => EXTENSION),
|
|
115
|
+
routes: mapped(contract.routes, ({ id }) => pageOf(id, contract)),
|
|
116
|
+
settings: Object.fromEntries(sections.map(([name]) => [name, SECTION]))
|
|
117
|
+
},
|
|
118
|
+
contract
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Returns the definition of a product that runs one plugin: the plugin from its manifest, and each
|
|
123
|
+
* plugin beside it from its contract alone.
|
|
124
|
+
*
|
|
125
|
+
* @remarks
|
|
126
|
+
* A route of a plugin installed from its contract alone renders a page that names the route and
|
|
127
|
+
* renders each of the plugin's slots with its sample props. Such a plugin's extensions render the
|
|
128
|
+
* content they wrap, or nothing, and its commands resolve with nothing. Its settings sections
|
|
129
|
+
* without a schema name their plugin. The product's id is the plugin's, and its name is the key
|
|
130
|
+
* `plugin.name`, so the product's name is the plugin's own.
|
|
131
|
+
* @param options - The plugin's contract and manifest, its configuration, and the contracts beside
|
|
132
|
+
* it.
|
|
133
|
+
* @throws {@link Error} Where the manifest implements another contract.
|
|
134
|
+
*/
|
|
135
|
+
function standaloneProduct(options) {
|
|
136
|
+
const { beside = [], config, contract, manifest = placeholderOf(contract) } = options;
|
|
137
|
+
if (manifest.contract !== contract) throw new Error(`The manifest implements the contract of ${manifest.contract.pluginId}, not of ${contract.pluginId}.`);
|
|
138
|
+
return {
|
|
139
|
+
name: "plugin.name",
|
|
140
|
+
plugins: [{
|
|
141
|
+
config,
|
|
142
|
+
manifest
|
|
143
|
+
}, ...beside.map((one) => ({ manifest: placeholderOf(one) }))],
|
|
144
|
+
productId: contract.pluginId,
|
|
145
|
+
version: VERSION
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The members every manifest has, which no contract has.
|
|
150
|
+
*/
|
|
151
|
+
const MANIFEST_KEYS = [
|
|
152
|
+
"apiVersion",
|
|
153
|
+
"code",
|
|
154
|
+
"contract"
|
|
155
|
+
];
|
|
156
|
+
/**
|
|
157
|
+
* The members every contract has, which no manifest has.
|
|
158
|
+
*/
|
|
159
|
+
const CONTRACT_KEYS = ["pluginId", "routes"];
|
|
160
|
+
/**
|
|
161
|
+
* Returns true where a value is an object with every member a manifest has.
|
|
162
|
+
*/
|
|
163
|
+
function isManifest(value) {
|
|
164
|
+
return value instanceof Object && MANIFEST_KEYS.every((key) => key in value);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Returns true where a value is an object with every member a contract has.
|
|
168
|
+
*/
|
|
169
|
+
function isContract(value) {
|
|
170
|
+
return value instanceof Object && CONTRACT_KEYS.every((key) => key in value);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Returns the one export of a module the test accepts, however many names export it.
|
|
174
|
+
*
|
|
175
|
+
* @param standalone - The module, and where it comes from.
|
|
176
|
+
* @param test - Accepts the kind of export the module must have one of.
|
|
177
|
+
* @param kind - The kind of export, which an error names.
|
|
178
|
+
* @throws {@link Error} Where the module exports none of the kind, or several.
|
|
179
|
+
*/
|
|
180
|
+
function oneOf({ from, module }, test, kind) {
|
|
181
|
+
const found = [...new Set(Object.values(module).filter((value) => test(value)))];
|
|
182
|
+
const [one] = found;
|
|
183
|
+
if (one === void 0 || found.length > 1) throw new Error(`${from} exports ${String(found.length)} ${kind}s, and a standalone product takes one.`);
|
|
184
|
+
return one;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Returns the definition of a product that runs one plugin, from the plugin's manifest module and
|
|
188
|
+
* the module of each contract package beside it.
|
|
189
|
+
*
|
|
190
|
+
* @remarks
|
|
191
|
+
* The standalone layer of `vite-config-product` writes a definition that calls this with the
|
|
192
|
+
* modules it imports, so an author states package names and paths alone.
|
|
193
|
+
* @param plugin - The module that exports the plugin's manifest.
|
|
194
|
+
* @param beside - The module of each contract package installed beside the plugin.
|
|
195
|
+
* @throws {@link Error} Where a module exports no manifest or contract, or several, naming the
|
|
196
|
+
* module.
|
|
197
|
+
*/
|
|
198
|
+
function standaloneFrom(plugin, beside = []) {
|
|
199
|
+
const manifest = oneOf(plugin, isManifest, "plugin manifest");
|
|
200
|
+
return standaloneProduct({
|
|
201
|
+
beside: beside.map((one) => oneOf(one, isContract, "plugin contract")),
|
|
202
|
+
contract: manifest.contract,
|
|
203
|
+
manifest
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Returns the sources of a standalone product's host: a signed-in session with every permission and
|
|
208
|
+
* entitlement the product declares, every check on one resource the session's permissions admit
|
|
209
|
+
* allowed, every boolean flag on and every experiment at its default.
|
|
210
|
+
*
|
|
211
|
+
* @param product - The permissions and entitlements the installed plugins declare.
|
|
212
|
+
*/
|
|
213
|
+
function standaloneSources(product) {
|
|
214
|
+
const session = kept({
|
|
215
|
+
authenticated: true,
|
|
216
|
+
entitlements: product.entitlements.map(({ id }) => id),
|
|
217
|
+
permissions: product.permissions.map(({ id }) => id),
|
|
218
|
+
roles: []
|
|
219
|
+
});
|
|
220
|
+
const decider = kept(allowed);
|
|
221
|
+
/**
|
|
222
|
+
* Returns true where the session has the permission a check names.
|
|
223
|
+
*/
|
|
224
|
+
const permitted = ({ permission }) => session.get().permissions.includes(permission);
|
|
225
|
+
return {
|
|
226
|
+
access: {
|
|
227
|
+
allow: () => {
|
|
228
|
+
decider.set(allowed);
|
|
229
|
+
},
|
|
230
|
+
check: (checks) => {
|
|
231
|
+
const decide = decider.get();
|
|
232
|
+
return decide === void 0 ? PENDING : Promise.resolve(checks.map((check) => permitted(check) && decide(check)));
|
|
233
|
+
},
|
|
234
|
+
decide: decider.set,
|
|
235
|
+
deny: () => {
|
|
236
|
+
decider.set(denied);
|
|
237
|
+
},
|
|
238
|
+
pending: () => {
|
|
239
|
+
decider.set(void 0);
|
|
240
|
+
},
|
|
241
|
+
subscribe: (listener) => {
|
|
242
|
+
const stops = [decider.subscribe(listener), session.subscribe(listener)];
|
|
243
|
+
return () => {
|
|
244
|
+
for (const stop of stops) stop();
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
flags: FLAGS,
|
|
249
|
+
session: {
|
|
250
|
+
read: session.get,
|
|
251
|
+
set: session.set,
|
|
252
|
+
subscribe: session.subscribe
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
//#endregion
|
|
257
|
+
export { standaloneFrom, standaloneProduct, standaloneSources };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { c } from "react/compiler-runtime";
|
|
2
|
+
import { useTranslation } from "@stealthscale/provider-i18n";
|
|
3
|
+
//#region src/host/words.ts
|
|
4
|
+
/**
|
|
5
|
+
* Returns the reader of the plugins' words over an i18next instance.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* A plugin's catalogue belongs to the product, so the host's generated word types list none of
|
|
9
|
+
* its keys, and the reader looks them up with plain strings.
|
|
10
|
+
* @param i18n - The instance `useTranslation` returns.
|
|
11
|
+
*/
|
|
12
|
+
function pluginWordsOf(i18n) {
|
|
13
|
+
const untyped = i18n;
|
|
14
|
+
return {
|
|
15
|
+
exists: (pluginId, key) => untyped.exists(key, { ns: pluginId }),
|
|
16
|
+
t: (pluginId, key, values = {}) => untyped.t(key, {
|
|
17
|
+
...values,
|
|
18
|
+
ns: pluginId
|
|
19
|
+
})
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Returns the translator a settings section's form reads its words through: each key is looked up
|
|
24
|
+
* in the catalogue of the section's plugin, and the form's default is returned where none is found.
|
|
25
|
+
*
|
|
26
|
+
* @param i18n - The instance `useTranslation` returns.
|
|
27
|
+
* @param pluginId - Id of the plugin whose catalogue the form reads.
|
|
28
|
+
*/
|
|
29
|
+
function translatorOf(i18n, pluginId) {
|
|
30
|
+
const untyped = i18n;
|
|
31
|
+
return (keys, options) => untyped.t(keys, {
|
|
32
|
+
...options,
|
|
33
|
+
ns: pluginId
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Returns the product's name in the person's language, and renders again when the language
|
|
38
|
+
* changes.
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* The name is the key the product's definition states under `name`, translated in the product's
|
|
42
|
+
* own namespace, its id.
|
|
43
|
+
*/
|
|
44
|
+
function useProductName(product) {
|
|
45
|
+
const $ = c(4);
|
|
46
|
+
const { i18n } = useTranslation("host");
|
|
47
|
+
let t0;
|
|
48
|
+
if ($[0] !== i18n || $[1] !== product.name || $[2] !== product.productId) {
|
|
49
|
+
t0 = pluginWordsOf(i18n).t(product.productId, product.name);
|
|
50
|
+
$[0] = i18n;
|
|
51
|
+
$[1] = product.name;
|
|
52
|
+
$[2] = product.productId;
|
|
53
|
+
$[3] = t0;
|
|
54
|
+
} else t0 = $[3];
|
|
55
|
+
return t0;
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { translatorOf as n, useProductName as r, pluginWordsOf as t };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
{
|
|
2
|
+
"commands": {
|
|
3
|
+
"failed": "Could not run \"{{label}}\"."
|
|
4
|
+
},
|
|
5
|
+
"failed": {
|
|
6
|
+
"description": "Reload the page to start it again.",
|
|
7
|
+
"reload": "Reload",
|
|
8
|
+
"title": "{{product}} could not be shown"
|
|
9
|
+
},
|
|
10
|
+
"flags": {
|
|
11
|
+
"killSwitch": "Turns the whole plugin off"
|
|
12
|
+
},
|
|
13
|
+
"notFound": {
|
|
14
|
+
"off": {
|
|
15
|
+
"action": "Turn on {{plugin}}",
|
|
16
|
+
"description": "Turn {{plugin}} on to open this page.",
|
|
17
|
+
"title": "{{plugin}} is turned off"
|
|
18
|
+
},
|
|
19
|
+
"plain": {
|
|
20
|
+
"description": "Check the address, or go back to the page you came from.",
|
|
21
|
+
"title": "Page not found"
|
|
22
|
+
},
|
|
23
|
+
"quarantined": {
|
|
24
|
+
"action": "Try again",
|
|
25
|
+
"description": "It failed too many times in a row.",
|
|
26
|
+
"title": "This page stopped working"
|
|
27
|
+
},
|
|
28
|
+
"unavailable": {
|
|
29
|
+
"description": "{{plugin}} is unavailable for now. Try again later.",
|
|
30
|
+
"title": "{{plugin}} is unavailable"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"page": {
|
|
34
|
+
"failed": {
|
|
35
|
+
"description": "Reload the page, or try again later.",
|
|
36
|
+
"title": "This page could not be shown"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"palette": {
|
|
40
|
+
"commands": "Commands",
|
|
41
|
+
"count_one": "{{count}} result",
|
|
42
|
+
"count_other": "{{count}} results",
|
|
43
|
+
"goTo": "Go to",
|
|
44
|
+
"label": "Command palette",
|
|
45
|
+
"none": "No command matches.",
|
|
46
|
+
"search": "Search commands"
|
|
47
|
+
},
|
|
48
|
+
"plugins": {
|
|
49
|
+
"about": "Turn a plugin off to remove its pages, menus and settings for you alone.",
|
|
50
|
+
"always": "Always on",
|
|
51
|
+
"confirm": {
|
|
52
|
+
"action": "Turn off",
|
|
53
|
+
"description_one": "{{plugins}} needs it and turns off with it.",
|
|
54
|
+
"description_other": "{{plugins}} need it and turn off with it.",
|
|
55
|
+
"keep": "Keep on",
|
|
56
|
+
"title": "Turn off {{plugin}}?"
|
|
57
|
+
},
|
|
58
|
+
"reason": {
|
|
59
|
+
"condition": "Not available here",
|
|
60
|
+
"requirement": "Off while a plugin it needs is off",
|
|
61
|
+
"unavailable": "Unavailable for now"
|
|
62
|
+
},
|
|
63
|
+
"title": "Installed plugins"
|
|
64
|
+
},
|
|
65
|
+
"settings": {
|
|
66
|
+
"account": "Account",
|
|
67
|
+
"empty": "Nothing to set on this page",
|
|
68
|
+
"failed": {
|
|
69
|
+
"description": "Reload the page, or try again later.",
|
|
70
|
+
"title": "This section could not be shown"
|
|
71
|
+
},
|
|
72
|
+
"menu": "Settings pages",
|
|
73
|
+
"plugins": "Plugins",
|
|
74
|
+
"save": "Save",
|
|
75
|
+
"saved": "Settings saved",
|
|
76
|
+
"title": "Settings"
|
|
77
|
+
},
|
|
78
|
+
"standalone": {
|
|
79
|
+
"page": "{{plugin}} is installed from its contract alone, so this page is a placeholder. Its slots render with their sample props.",
|
|
80
|
+
"panel": {
|
|
81
|
+
"access": {
|
|
82
|
+
"allow": "Allow",
|
|
83
|
+
"deny": "Deny",
|
|
84
|
+
"pending": "Pending",
|
|
85
|
+
"title": "Checks on one resource"
|
|
86
|
+
},
|
|
87
|
+
"data": {
|
|
88
|
+
"modes": {
|
|
89
|
+
"conflict": "Refuse as a conflict",
|
|
90
|
+
"delayed": "Sample after 2 seconds",
|
|
91
|
+
"forbidden": "Refuse as forbidden",
|
|
92
|
+
"invalid": "Refuse as invalid",
|
|
93
|
+
"network": "Fail on the network",
|
|
94
|
+
"not-found": "Refuse as not found",
|
|
95
|
+
"sample": "Sample",
|
|
96
|
+
"server": "Fail on the server",
|
|
97
|
+
"unauthenticated": "Refuse as signed out"
|
|
98
|
+
},
|
|
99
|
+
"title": "Operations"
|
|
100
|
+
},
|
|
101
|
+
"flags": {
|
|
102
|
+
"title": "Feature flags"
|
|
103
|
+
},
|
|
104
|
+
"page": {
|
|
105
|
+
"route": "Page",
|
|
106
|
+
"title": "Page"
|
|
107
|
+
},
|
|
108
|
+
"plugin": {
|
|
109
|
+
"kill": "Allowed by its kill switch",
|
|
110
|
+
"switch": "Switched on",
|
|
111
|
+
"title": "Plugin"
|
|
112
|
+
},
|
|
113
|
+
"session": {
|
|
114
|
+
"entitlements": "Entitlements",
|
|
115
|
+
"permissions": "Permissions",
|
|
116
|
+
"signedIn": "Signed in",
|
|
117
|
+
"title": "Session"
|
|
118
|
+
},
|
|
119
|
+
"shell": {
|
|
120
|
+
"colorMode": "Color mode",
|
|
121
|
+
"dark": "Dark",
|
|
122
|
+
"language": "Language",
|
|
123
|
+
"light": "Light",
|
|
124
|
+
"system": "System",
|
|
125
|
+
"theme": "Theme",
|
|
126
|
+
"title": "Display"
|
|
127
|
+
},
|
|
128
|
+
"title": "Development panel"
|
|
129
|
+
},
|
|
130
|
+
"section": "{{plugin}} is installed from its contract alone, so this section is a placeholder."
|
|
131
|
+
},
|
|
132
|
+
"toasts": {
|
|
133
|
+
"label": "Notifications"
|
|
134
|
+
}
|
|
135
|
+
}
|