nfkit 1.0.19 → 1.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +307 -18
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +302 -18
- package/dist/index.mjs.map +4 -4
- package/dist/src/app-context/app-context.d.ts +27 -0
- package/dist/src/app-context/app-service-base.d.ts +7 -0
- package/dist/src/app-context/index.d.ts +3 -0
- package/dist/src/app-context/promise-utils.d.ts +20 -0
- package/dist/src/app-context/types.d.ts +32 -0
- package/dist/src/dual-object.d.ts +4 -3
- package/dist/src/i18n/i18n.d.ts +0 -1
- package/dist/src/i18n/types.d.ts +4 -1
- package/dist/src/types.d.ts +5 -0
- package/index.ts +1 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -89,6 +89,10 @@ function makeProxy(node) {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
// src/dual-object.ts
|
|
92
|
+
var DUAL_PENDING = Symbol("dual.pending");
|
|
93
|
+
var throwDualPending = () => {
|
|
94
|
+
throw DUAL_PENDING;
|
|
95
|
+
};
|
|
92
96
|
var isThenKey = (k) => k === "then" || k === "catch" || k === "finally";
|
|
93
97
|
function dualizeAny(sync, asyncFn, options) {
|
|
94
98
|
let state = "undecided";
|
|
@@ -122,6 +126,10 @@ function dualizeAny(sync, asyncFn, options) {
|
|
|
122
126
|
value = sync();
|
|
123
127
|
state = "fulfilled";
|
|
124
128
|
} catch (e) {
|
|
129
|
+
if (e === DUAL_PENDING) {
|
|
130
|
+
startAsync();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
125
133
|
reason = e;
|
|
126
134
|
state = "rejected";
|
|
127
135
|
}
|
|
@@ -180,6 +188,9 @@ function dualizeAny(sync, asyncFn, options) {
|
|
|
180
188
|
case "undecided": {
|
|
181
189
|
ensureSync();
|
|
182
190
|
if (state === "fulfilled") return getFrom(value, prop);
|
|
191
|
+
if (state === "pending") {
|
|
192
|
+
throw new TypeError("Value is not ready yet. Please await it first.");
|
|
193
|
+
}
|
|
183
194
|
if (state === "rejected") throw reason;
|
|
184
195
|
throw new TypeError("Invalid state transition");
|
|
185
196
|
}
|
|
@@ -1002,36 +1013,44 @@ var patchStringInObject = async (obj, cb) => {
|
|
|
1002
1013
|
};
|
|
1003
1014
|
|
|
1004
1015
|
// src/i18n/i18n.ts
|
|
1005
|
-
var
|
|
1006
|
-
constructor(
|
|
1007
|
-
|
|
1008
|
-
this.locales = new Set(this.options.locales);
|
|
1009
|
-
this.defaultLocale = this.options.defaultLocale ?? this.options.locales[0];
|
|
1010
|
-
this.mw = new MiddlewareDispatcher({
|
|
1016
|
+
var I18nMiddlewareDispatcher = class extends DynamicMiddlewareDispatcher {
|
|
1017
|
+
constructor() {
|
|
1018
|
+
super({
|
|
1011
1019
|
acceptResult: (res) => res != null,
|
|
1012
1020
|
errorHandler: (e) => {
|
|
1013
1021
|
throw e;
|
|
1014
1022
|
}
|
|
1015
1023
|
});
|
|
1016
|
-
this.
|
|
1024
|
+
this.middlewares = [];
|
|
1025
|
+
}
|
|
1026
|
+
async buildMiddlewares() {
|
|
1027
|
+
return this.middlewares.map(
|
|
1028
|
+
(mw) => (locale, text, ...args) => {
|
|
1029
|
+
const ex = args.slice(0, -1);
|
|
1030
|
+
const next = args[args.length - 1];
|
|
1031
|
+
return mw(locale, text, next, ...ex);
|
|
1032
|
+
}
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
var I18n = class {
|
|
1037
|
+
constructor(options) {
|
|
1038
|
+
this.options = options;
|
|
1039
|
+
this.locales = new Set(this.options.locales);
|
|
1040
|
+
this.defaultLocale = this.options.defaultLocale ?? this.options.locales[0];
|
|
1041
|
+
this.mw = new I18nMiddlewareDispatcher();
|
|
1017
1042
|
}
|
|
1018
1043
|
middleware(mw, prior = false) {
|
|
1019
|
-
this.mw.middleware((locale, text, ...args) => {
|
|
1020
|
-
const ex = args.slice(0, -1);
|
|
1021
|
-
const next = args[args.length - 1];
|
|
1022
|
-
return mw(locale, text, next, ...ex);
|
|
1023
|
-
}, prior);
|
|
1024
1044
|
if (prior) {
|
|
1025
|
-
this.
|
|
1045
|
+
this.mw.middlewares.unshift(mw);
|
|
1026
1046
|
} else {
|
|
1027
|
-
this.
|
|
1047
|
+
this.mw.middlewares.push(mw);
|
|
1028
1048
|
}
|
|
1029
1049
|
return this;
|
|
1030
1050
|
}
|
|
1031
1051
|
removeMiddleware(mw) {
|
|
1032
|
-
const idx = this.
|
|
1052
|
+
const idx = this.mw.middlewares.indexOf(mw);
|
|
1033
1053
|
if (idx >= 0) {
|
|
1034
|
-
this.shadowMiddlewares.splice(idx, 1);
|
|
1035
1054
|
this.mw.middlewares.splice(idx, 1);
|
|
1036
1055
|
}
|
|
1037
1056
|
return this;
|
|
@@ -1182,11 +1201,11 @@ var observeDiff = (obj, cb) => {
|
|
|
1182
1201
|
// src/memorize.ts
|
|
1183
1202
|
var Memorize = () => {
|
|
1184
1203
|
const cache = /* @__PURE__ */ new WeakMap();
|
|
1185
|
-
const
|
|
1204
|
+
const isPromiseLike2 = (v) => v != null && typeof v.then === "function" && typeof v.catch === "function";
|
|
1186
1205
|
const getOrSet = (instance, compute) => {
|
|
1187
1206
|
if (cache.has(instance)) return cache.get(instance);
|
|
1188
1207
|
const result = compute();
|
|
1189
|
-
if (
|
|
1208
|
+
if (isPromiseLike2(result)) {
|
|
1190
1209
|
const wrapped = result.catch((err) => {
|
|
1191
1210
|
cache.delete(instance);
|
|
1192
1211
|
throw err;
|
|
@@ -1219,8 +1238,271 @@ var Memorize = () => {
|
|
|
1219
1238
|
var makeArray = (value) => {
|
|
1220
1239
|
return Array.isArray(value) ? value : [value];
|
|
1221
1240
|
};
|
|
1241
|
+
|
|
1242
|
+
// src/app-context/promise-utils.ts
|
|
1243
|
+
var promiseStates = /* @__PURE__ */ new WeakMap();
|
|
1244
|
+
var isPromiseLike = (value) => !!value && typeof value.then === "function";
|
|
1245
|
+
var trackPromise = (promise) => {
|
|
1246
|
+
const existing = promiseStates.get(promise);
|
|
1247
|
+
if (existing) return existing;
|
|
1248
|
+
const state = { status: "pending" };
|
|
1249
|
+
promiseStates.set(promise, state);
|
|
1250
|
+
promise.then(
|
|
1251
|
+
(value) => {
|
|
1252
|
+
state.status = "fulfilled";
|
|
1253
|
+
state.value = value;
|
|
1254
|
+
},
|
|
1255
|
+
(error) => {
|
|
1256
|
+
state.status = "rejected";
|
|
1257
|
+
state.error = error;
|
|
1258
|
+
}
|
|
1259
|
+
);
|
|
1260
|
+
return state;
|
|
1261
|
+
};
|
|
1262
|
+
var wrapMaybePromise = (value, options) => {
|
|
1263
|
+
if (!isPromiseLike(value)) return value;
|
|
1264
|
+
const promise = Promise.resolve(value);
|
|
1265
|
+
const state = trackPromise(promise);
|
|
1266
|
+
if (state.status === "fulfilled") return state.value;
|
|
1267
|
+
if (state.status === "rejected") throw state.error;
|
|
1268
|
+
return dualizeAny(
|
|
1269
|
+
() => {
|
|
1270
|
+
const current = trackPromise(promise);
|
|
1271
|
+
if (current.status === "fulfilled") return current.value;
|
|
1272
|
+
if (current.status === "rejected") throw current.error;
|
|
1273
|
+
throwDualPending();
|
|
1274
|
+
},
|
|
1275
|
+
() => promise,
|
|
1276
|
+
{
|
|
1277
|
+
// Intentionally hide strict method return type here.
|
|
1278
|
+
asyncMethods: Array.from(options?.methodKeys ?? [])
|
|
1279
|
+
}
|
|
1280
|
+
);
|
|
1281
|
+
};
|
|
1282
|
+
var createAsyncMethod = (inst, key) => (...args) => Promise.resolve(inst).then((resolved) => {
|
|
1283
|
+
const fn = resolved?.[key];
|
|
1284
|
+
if (typeof fn !== "function") {
|
|
1285
|
+
throw new TypeError("Target method is not a function");
|
|
1286
|
+
}
|
|
1287
|
+
return fn.apply(resolved, args);
|
|
1288
|
+
});
|
|
1289
|
+
|
|
1290
|
+
// src/app-context/app-context.ts
|
|
1291
|
+
var ProvidePrefix = "provide:";
|
|
1292
|
+
var getMethodDescriptor = (cls, key) => {
|
|
1293
|
+
let proto = cls.prototype;
|
|
1294
|
+
while (proto && proto !== Object.prototype) {
|
|
1295
|
+
const desc = Object.getOwnPropertyDescriptor(proto, key);
|
|
1296
|
+
if (desc) return desc;
|
|
1297
|
+
proto = Object.getPrototypeOf(proto);
|
|
1298
|
+
}
|
|
1299
|
+
return void 0;
|
|
1300
|
+
};
|
|
1301
|
+
var flushPendingSets = (entry) => {
|
|
1302
|
+
if (isPromiseLike(entry.inst)) return;
|
|
1303
|
+
if (!entry.pendingSets.length) return;
|
|
1304
|
+
for (const item of entry.pendingSets) {
|
|
1305
|
+
entry.inst[item.key] = item.value;
|
|
1306
|
+
}
|
|
1307
|
+
entry.pendingSets.length = 0;
|
|
1308
|
+
};
|
|
1309
|
+
var resolveEntryIfNeeded = async (entry) => {
|
|
1310
|
+
if (isPromiseLike(entry.inst)) {
|
|
1311
|
+
entry.inst = await entry.inst;
|
|
1312
|
+
}
|
|
1313
|
+
flushPendingSets(entry);
|
|
1314
|
+
return entry.inst;
|
|
1315
|
+
};
|
|
1316
|
+
var AppContextCore = class {
|
|
1317
|
+
constructor() {
|
|
1318
|
+
this.registry = /* @__PURE__ */ new Map();
|
|
1319
|
+
this.loadSeq = [];
|
|
1320
|
+
this.objectSteps = [];
|
|
1321
|
+
}
|
|
1322
|
+
provide(cls, ...args) {
|
|
1323
|
+
const last = args[args.length - 1];
|
|
1324
|
+
const hasOptions = !!last && typeof last === "object" && ("provide" in last || "merge" in last || "useValue" in last || "useFactory" in last || "useClass" in last);
|
|
1325
|
+
const options = hasOptions ? last : void 0;
|
|
1326
|
+
const _args = hasOptions ? args.slice(0, -1) : args;
|
|
1327
|
+
const inst = options?.useValue ?? (options?.useFactory ? options.useFactory(this, ..._args) : new (options?.useClass ?? cls)(this, ..._args));
|
|
1328
|
+
const classRef = cls;
|
|
1329
|
+
const provideKey = options?.provide ? ProvidePrefix + String(options.provide) : void 0;
|
|
1330
|
+
const methodKeys = /* @__PURE__ */ new Set();
|
|
1331
|
+
for (const name of Object.getOwnPropertyNames(cls.prototype)) {
|
|
1332
|
+
if (name === "constructor") continue;
|
|
1333
|
+
const desc = Object.getOwnPropertyDescriptor(cls.prototype, name);
|
|
1334
|
+
if (desc && typeof desc.value === "function") {
|
|
1335
|
+
methodKeys.add(name);
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
const entry = {
|
|
1339
|
+
classRef,
|
|
1340
|
+
inst,
|
|
1341
|
+
methodKeys,
|
|
1342
|
+
pendingSets: []
|
|
1343
|
+
};
|
|
1344
|
+
this.registry.set(classRef, entry);
|
|
1345
|
+
if (provideKey) this.registry.set(provideKey, entry);
|
|
1346
|
+
this.loadSeq.push(entry);
|
|
1347
|
+
if (options?.provide) {
|
|
1348
|
+
const prop = options.provide;
|
|
1349
|
+
const step = (ctx) => {
|
|
1350
|
+
Object.defineProperty(ctx, prop, {
|
|
1351
|
+
enumerable: true,
|
|
1352
|
+
configurable: true,
|
|
1353
|
+
get: () => {
|
|
1354
|
+
const currentEntry = ctx.registry.get(classRef);
|
|
1355
|
+
return wrapMaybePromise(currentEntry?.inst, { methodKeys });
|
|
1356
|
+
}
|
|
1357
|
+
});
|
|
1358
|
+
};
|
|
1359
|
+
step(this);
|
|
1360
|
+
this.objectSteps.push(step);
|
|
1361
|
+
}
|
|
1362
|
+
if (options?.merge?.length) {
|
|
1363
|
+
for (const key of options.merge) {
|
|
1364
|
+
const desc = getMethodDescriptor(cls, key);
|
|
1365
|
+
const isMethod = !!desc && typeof desc.value === "function";
|
|
1366
|
+
const step = (ctx) => {
|
|
1367
|
+
if (isMethod) {
|
|
1368
|
+
Object.defineProperty(ctx, key, {
|
|
1369
|
+
enumerable: true,
|
|
1370
|
+
configurable: true,
|
|
1371
|
+
get: () => {
|
|
1372
|
+
const currentEntry = ctx.registry.get(classRef);
|
|
1373
|
+
const currentInst = currentEntry?.inst;
|
|
1374
|
+
if (isPromiseLike(currentInst))
|
|
1375
|
+
return createAsyncMethod(currentInst, key);
|
|
1376
|
+
const fn = currentInst?.[key];
|
|
1377
|
+
return typeof fn === "function" ? fn.bind(currentInst) : fn;
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
Object.defineProperty(ctx, key, {
|
|
1383
|
+
enumerable: true,
|
|
1384
|
+
configurable: true,
|
|
1385
|
+
get: () => {
|
|
1386
|
+
const currentEntry = ctx.registry.get(classRef);
|
|
1387
|
+
const target = wrapMaybePromise(currentEntry?.inst);
|
|
1388
|
+
return target?.[key];
|
|
1389
|
+
},
|
|
1390
|
+
set: (value) => {
|
|
1391
|
+
const currentEntry = ctx.registry.get(classRef);
|
|
1392
|
+
if (!currentEntry) return;
|
|
1393
|
+
if (!isPromiseLike(currentEntry.inst)) {
|
|
1394
|
+
currentEntry.inst[key] = value;
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
const state = trackPromise(currentEntry.inst);
|
|
1398
|
+
if (state.status === "fulfilled") {
|
|
1399
|
+
currentEntry.inst = state.value;
|
|
1400
|
+
flushPendingSets(currentEntry);
|
|
1401
|
+
currentEntry.inst[key] = value;
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
if (state.status === "rejected") throw state.error;
|
|
1405
|
+
currentEntry.pendingSets.push({ key, value });
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
};
|
|
1409
|
+
step(this);
|
|
1410
|
+
this.objectSteps.push(step);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
return this;
|
|
1414
|
+
}
|
|
1415
|
+
get(cls) {
|
|
1416
|
+
const key = cls;
|
|
1417
|
+
if (!this.registry.has(key)) {
|
|
1418
|
+
throw new Error(`Service not provided: ${cls.name}`);
|
|
1419
|
+
}
|
|
1420
|
+
const entry = this.registry.get(key);
|
|
1421
|
+
const inst = entry.inst;
|
|
1422
|
+
if (isPromiseLike(inst)) {
|
|
1423
|
+
const state = trackPromise(inst);
|
|
1424
|
+
if (state.status === "fulfilled") {
|
|
1425
|
+
entry.inst = state.value;
|
|
1426
|
+
flushPendingSets(entry);
|
|
1427
|
+
return state.value;
|
|
1428
|
+
}
|
|
1429
|
+
if (state.status === "rejected") throw state.error;
|
|
1430
|
+
return wrapMaybePromise(inst, {
|
|
1431
|
+
methodKeys: entry.methodKeys
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
flushPendingSets(entry);
|
|
1435
|
+
return inst;
|
|
1436
|
+
}
|
|
1437
|
+
async getAsync(cls) {
|
|
1438
|
+
const key = cls;
|
|
1439
|
+
if (!this.registry.has(key)) {
|
|
1440
|
+
throw new Error(`Service not provided: ${cls.name}`);
|
|
1441
|
+
}
|
|
1442
|
+
const entry = this.registry.get(key);
|
|
1443
|
+
const resolved = await resolveEntryIfNeeded(entry);
|
|
1444
|
+
return resolved;
|
|
1445
|
+
}
|
|
1446
|
+
use(...ctxes) {
|
|
1447
|
+
for (const ctx of ctxes) {
|
|
1448
|
+
const other = ctx;
|
|
1449
|
+
const entryMap = /* @__PURE__ */ new Map();
|
|
1450
|
+
if (Array.isArray(other?.loadSeq)) {
|
|
1451
|
+
const copiedSeq = other.loadSeq.map((item) => ({
|
|
1452
|
+
...item,
|
|
1453
|
+
methodKeys: new Set(item.methodKeys ?? []),
|
|
1454
|
+
pendingSets: [...item.pendingSets ?? []]
|
|
1455
|
+
}));
|
|
1456
|
+
other.loadSeq.forEach((item, index) => {
|
|
1457
|
+
entryMap.set(item, copiedSeq[index]);
|
|
1458
|
+
});
|
|
1459
|
+
this.loadSeq.push(...copiedSeq);
|
|
1460
|
+
}
|
|
1461
|
+
if (other?.registry instanceof Map) {
|
|
1462
|
+
for (const [key, value] of other.registry.entries()) {
|
|
1463
|
+
this.registry.set(key, entryMap.get(value) ?? value);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
if (Array.isArray(other?.objectSteps)) {
|
|
1467
|
+
this.objectSteps.push(...other.objectSteps);
|
|
1468
|
+
for (const step of other.objectSteps) {
|
|
1469
|
+
step(this);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
return this;
|
|
1474
|
+
}
|
|
1475
|
+
define() {
|
|
1476
|
+
return this;
|
|
1477
|
+
}
|
|
1478
|
+
async start() {
|
|
1479
|
+
for (const entry of this.loadSeq) {
|
|
1480
|
+
await resolveEntryIfNeeded(entry);
|
|
1481
|
+
}
|
|
1482
|
+
for (const entry of this.loadSeq) {
|
|
1483
|
+
const inst = entry.inst;
|
|
1484
|
+
if (inst && typeof inst.init === "function") {
|
|
1485
|
+
await inst.init();
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
return this;
|
|
1489
|
+
}
|
|
1490
|
+
};
|
|
1491
|
+
var createAppContext = () => new AppContextCore();
|
|
1492
|
+
|
|
1493
|
+
// src/app-context/app-service-base.ts
|
|
1494
|
+
var AppServiceBase = class {
|
|
1495
|
+
constructor(ctx, ...args) {
|
|
1496
|
+
this.ctx = ctx;
|
|
1497
|
+
}
|
|
1498
|
+
async init() {
|
|
1499
|
+
}
|
|
1500
|
+
};
|
|
1222
1501
|
export {
|
|
1223
1502
|
AbortedError,
|
|
1503
|
+
AppContextCore,
|
|
1504
|
+
AppServiceBase,
|
|
1505
|
+
DUAL_PENDING,
|
|
1224
1506
|
DynamicMiddlewareDispatcher,
|
|
1225
1507
|
I18n,
|
|
1226
1508
|
I18nLookupMiddleware,
|
|
@@ -1231,11 +1513,13 @@ export {
|
|
|
1231
1513
|
WF_NODE,
|
|
1232
1514
|
WorkflowDispatcher,
|
|
1233
1515
|
abortable,
|
|
1516
|
+
createAppContext,
|
|
1234
1517
|
createI18nLookupMiddleware,
|
|
1235
1518
|
dualizeAny,
|
|
1236
1519
|
makeArray,
|
|
1237
1520
|
observeDiff,
|
|
1238
1521
|
patchStringInObject,
|
|
1522
|
+
throwDualPending,
|
|
1239
1523
|
workflow
|
|
1240
1524
|
};
|
|
1241
1525
|
//# sourceMappingURL=index.mjs.map
|