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.cjs
CHANGED
|
@@ -20,6 +20,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
var index_exports = {};
|
|
21
21
|
__export(index_exports, {
|
|
22
22
|
AbortedError: () => AbortedError,
|
|
23
|
+
AppContextCore: () => AppContextCore,
|
|
24
|
+
AppServiceBase: () => AppServiceBase,
|
|
25
|
+
DUAL_PENDING: () => DUAL_PENDING,
|
|
23
26
|
DynamicMiddlewareDispatcher: () => DynamicMiddlewareDispatcher,
|
|
24
27
|
I18n: () => I18n,
|
|
25
28
|
I18nLookupMiddleware: () => I18nLookupMiddleware,
|
|
@@ -30,11 +33,13 @@ __export(index_exports, {
|
|
|
30
33
|
WF_NODE: () => WF_NODE,
|
|
31
34
|
WorkflowDispatcher: () => WorkflowDispatcher,
|
|
32
35
|
abortable: () => abortable,
|
|
36
|
+
createAppContext: () => createAppContext,
|
|
33
37
|
createI18nLookupMiddleware: () => createI18nLookupMiddleware,
|
|
34
38
|
dualizeAny: () => dualizeAny,
|
|
35
39
|
makeArray: () => makeArray,
|
|
36
40
|
observeDiff: () => observeDiff,
|
|
37
41
|
patchStringInObject: () => patchStringInObject,
|
|
42
|
+
throwDualPending: () => throwDualPending,
|
|
38
43
|
workflow: () => workflow
|
|
39
44
|
});
|
|
40
45
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -130,6 +135,10 @@ function makeProxy(node) {
|
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
// src/dual-object.ts
|
|
138
|
+
var DUAL_PENDING = Symbol("dual.pending");
|
|
139
|
+
var throwDualPending = () => {
|
|
140
|
+
throw DUAL_PENDING;
|
|
141
|
+
};
|
|
133
142
|
var isThenKey = (k) => k === "then" || k === "catch" || k === "finally";
|
|
134
143
|
function dualizeAny(sync, asyncFn, options) {
|
|
135
144
|
let state = "undecided";
|
|
@@ -163,6 +172,10 @@ function dualizeAny(sync, asyncFn, options) {
|
|
|
163
172
|
value = sync();
|
|
164
173
|
state = "fulfilled";
|
|
165
174
|
} catch (e) {
|
|
175
|
+
if (e === DUAL_PENDING) {
|
|
176
|
+
startAsync();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
166
179
|
reason = e;
|
|
167
180
|
state = "rejected";
|
|
168
181
|
}
|
|
@@ -221,6 +234,9 @@ function dualizeAny(sync, asyncFn, options) {
|
|
|
221
234
|
case "undecided": {
|
|
222
235
|
ensureSync();
|
|
223
236
|
if (state === "fulfilled") return getFrom(value, prop);
|
|
237
|
+
if (state === "pending") {
|
|
238
|
+
throw new TypeError("Value is not ready yet. Please await it first.");
|
|
239
|
+
}
|
|
224
240
|
if (state === "rejected") throw reason;
|
|
225
241
|
throw new TypeError("Invalid state transition");
|
|
226
242
|
}
|
|
@@ -1043,36 +1059,44 @@ var patchStringInObject = async (obj, cb) => {
|
|
|
1043
1059
|
};
|
|
1044
1060
|
|
|
1045
1061
|
// src/i18n/i18n.ts
|
|
1046
|
-
var
|
|
1047
|
-
constructor(
|
|
1048
|
-
|
|
1049
|
-
this.locales = new Set(this.options.locales);
|
|
1050
|
-
this.defaultLocale = this.options.defaultLocale ?? this.options.locales[0];
|
|
1051
|
-
this.mw = new MiddlewareDispatcher({
|
|
1062
|
+
var I18nMiddlewareDispatcher = class extends DynamicMiddlewareDispatcher {
|
|
1063
|
+
constructor() {
|
|
1064
|
+
super({
|
|
1052
1065
|
acceptResult: (res) => res != null,
|
|
1053
1066
|
errorHandler: (e) => {
|
|
1054
1067
|
throw e;
|
|
1055
1068
|
}
|
|
1056
1069
|
});
|
|
1057
|
-
this.
|
|
1070
|
+
this.middlewares = [];
|
|
1071
|
+
}
|
|
1072
|
+
async buildMiddlewares() {
|
|
1073
|
+
return this.middlewares.map(
|
|
1074
|
+
(mw) => (locale, text, ...args) => {
|
|
1075
|
+
const ex = args.slice(0, -1);
|
|
1076
|
+
const next = args[args.length - 1];
|
|
1077
|
+
return mw(locale, text, next, ...ex);
|
|
1078
|
+
}
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
var I18n = class {
|
|
1083
|
+
constructor(options) {
|
|
1084
|
+
this.options = options;
|
|
1085
|
+
this.locales = new Set(this.options.locales);
|
|
1086
|
+
this.defaultLocale = this.options.defaultLocale ?? this.options.locales[0];
|
|
1087
|
+
this.mw = new I18nMiddlewareDispatcher();
|
|
1058
1088
|
}
|
|
1059
1089
|
middleware(mw, prior = false) {
|
|
1060
|
-
this.mw.middleware((locale, text, ...args) => {
|
|
1061
|
-
const ex = args.slice(0, -1);
|
|
1062
|
-
const next = args[args.length - 1];
|
|
1063
|
-
return mw(locale, text, next, ...ex);
|
|
1064
|
-
}, prior);
|
|
1065
1090
|
if (prior) {
|
|
1066
|
-
this.
|
|
1091
|
+
this.mw.middlewares.unshift(mw);
|
|
1067
1092
|
} else {
|
|
1068
|
-
this.
|
|
1093
|
+
this.mw.middlewares.push(mw);
|
|
1069
1094
|
}
|
|
1070
1095
|
return this;
|
|
1071
1096
|
}
|
|
1072
1097
|
removeMiddleware(mw) {
|
|
1073
|
-
const idx = this.
|
|
1098
|
+
const idx = this.mw.middlewares.indexOf(mw);
|
|
1074
1099
|
if (idx >= 0) {
|
|
1075
|
-
this.shadowMiddlewares.splice(idx, 1);
|
|
1076
1100
|
this.mw.middlewares.splice(idx, 1);
|
|
1077
1101
|
}
|
|
1078
1102
|
return this;
|
|
@@ -1223,11 +1247,11 @@ var observeDiff = (obj, cb) => {
|
|
|
1223
1247
|
// src/memorize.ts
|
|
1224
1248
|
var Memorize = () => {
|
|
1225
1249
|
const cache = /* @__PURE__ */ new WeakMap();
|
|
1226
|
-
const
|
|
1250
|
+
const isPromiseLike2 = (v) => v != null && typeof v.then === "function" && typeof v.catch === "function";
|
|
1227
1251
|
const getOrSet = (instance, compute) => {
|
|
1228
1252
|
if (cache.has(instance)) return cache.get(instance);
|
|
1229
1253
|
const result = compute();
|
|
1230
|
-
if (
|
|
1254
|
+
if (isPromiseLike2(result)) {
|
|
1231
1255
|
const wrapped = result.catch((err) => {
|
|
1232
1256
|
cache.delete(instance);
|
|
1233
1257
|
throw err;
|
|
@@ -1260,9 +1284,272 @@ var Memorize = () => {
|
|
|
1260
1284
|
var makeArray = (value) => {
|
|
1261
1285
|
return Array.isArray(value) ? value : [value];
|
|
1262
1286
|
};
|
|
1287
|
+
|
|
1288
|
+
// src/app-context/promise-utils.ts
|
|
1289
|
+
var promiseStates = /* @__PURE__ */ new WeakMap();
|
|
1290
|
+
var isPromiseLike = (value) => !!value && typeof value.then === "function";
|
|
1291
|
+
var trackPromise = (promise) => {
|
|
1292
|
+
const existing = promiseStates.get(promise);
|
|
1293
|
+
if (existing) return existing;
|
|
1294
|
+
const state = { status: "pending" };
|
|
1295
|
+
promiseStates.set(promise, state);
|
|
1296
|
+
promise.then(
|
|
1297
|
+
(value) => {
|
|
1298
|
+
state.status = "fulfilled";
|
|
1299
|
+
state.value = value;
|
|
1300
|
+
},
|
|
1301
|
+
(error) => {
|
|
1302
|
+
state.status = "rejected";
|
|
1303
|
+
state.error = error;
|
|
1304
|
+
}
|
|
1305
|
+
);
|
|
1306
|
+
return state;
|
|
1307
|
+
};
|
|
1308
|
+
var wrapMaybePromise = (value, options) => {
|
|
1309
|
+
if (!isPromiseLike(value)) return value;
|
|
1310
|
+
const promise = Promise.resolve(value);
|
|
1311
|
+
const state = trackPromise(promise);
|
|
1312
|
+
if (state.status === "fulfilled") return state.value;
|
|
1313
|
+
if (state.status === "rejected") throw state.error;
|
|
1314
|
+
return dualizeAny(
|
|
1315
|
+
() => {
|
|
1316
|
+
const current = trackPromise(promise);
|
|
1317
|
+
if (current.status === "fulfilled") return current.value;
|
|
1318
|
+
if (current.status === "rejected") throw current.error;
|
|
1319
|
+
throwDualPending();
|
|
1320
|
+
},
|
|
1321
|
+
() => promise,
|
|
1322
|
+
{
|
|
1323
|
+
// Intentionally hide strict method return type here.
|
|
1324
|
+
asyncMethods: Array.from(options?.methodKeys ?? [])
|
|
1325
|
+
}
|
|
1326
|
+
);
|
|
1327
|
+
};
|
|
1328
|
+
var createAsyncMethod = (inst, key) => (...args) => Promise.resolve(inst).then((resolved) => {
|
|
1329
|
+
const fn = resolved?.[key];
|
|
1330
|
+
if (typeof fn !== "function") {
|
|
1331
|
+
throw new TypeError("Target method is not a function");
|
|
1332
|
+
}
|
|
1333
|
+
return fn.apply(resolved, args);
|
|
1334
|
+
});
|
|
1335
|
+
|
|
1336
|
+
// src/app-context/app-context.ts
|
|
1337
|
+
var ProvidePrefix = "provide:";
|
|
1338
|
+
var getMethodDescriptor = (cls, key) => {
|
|
1339
|
+
let proto = cls.prototype;
|
|
1340
|
+
while (proto && proto !== Object.prototype) {
|
|
1341
|
+
const desc = Object.getOwnPropertyDescriptor(proto, key);
|
|
1342
|
+
if (desc) return desc;
|
|
1343
|
+
proto = Object.getPrototypeOf(proto);
|
|
1344
|
+
}
|
|
1345
|
+
return void 0;
|
|
1346
|
+
};
|
|
1347
|
+
var flushPendingSets = (entry) => {
|
|
1348
|
+
if (isPromiseLike(entry.inst)) return;
|
|
1349
|
+
if (!entry.pendingSets.length) return;
|
|
1350
|
+
for (const item of entry.pendingSets) {
|
|
1351
|
+
entry.inst[item.key] = item.value;
|
|
1352
|
+
}
|
|
1353
|
+
entry.pendingSets.length = 0;
|
|
1354
|
+
};
|
|
1355
|
+
var resolveEntryIfNeeded = async (entry) => {
|
|
1356
|
+
if (isPromiseLike(entry.inst)) {
|
|
1357
|
+
entry.inst = await entry.inst;
|
|
1358
|
+
}
|
|
1359
|
+
flushPendingSets(entry);
|
|
1360
|
+
return entry.inst;
|
|
1361
|
+
};
|
|
1362
|
+
var AppContextCore = class {
|
|
1363
|
+
constructor() {
|
|
1364
|
+
this.registry = /* @__PURE__ */ new Map();
|
|
1365
|
+
this.loadSeq = [];
|
|
1366
|
+
this.objectSteps = [];
|
|
1367
|
+
}
|
|
1368
|
+
provide(cls, ...args) {
|
|
1369
|
+
const last = args[args.length - 1];
|
|
1370
|
+
const hasOptions = !!last && typeof last === "object" && ("provide" in last || "merge" in last || "useValue" in last || "useFactory" in last || "useClass" in last);
|
|
1371
|
+
const options = hasOptions ? last : void 0;
|
|
1372
|
+
const _args = hasOptions ? args.slice(0, -1) : args;
|
|
1373
|
+
const inst = options?.useValue ?? (options?.useFactory ? options.useFactory(this, ..._args) : new (options?.useClass ?? cls)(this, ..._args));
|
|
1374
|
+
const classRef = cls;
|
|
1375
|
+
const provideKey = options?.provide ? ProvidePrefix + String(options.provide) : void 0;
|
|
1376
|
+
const methodKeys = /* @__PURE__ */ new Set();
|
|
1377
|
+
for (const name of Object.getOwnPropertyNames(cls.prototype)) {
|
|
1378
|
+
if (name === "constructor") continue;
|
|
1379
|
+
const desc = Object.getOwnPropertyDescriptor(cls.prototype, name);
|
|
1380
|
+
if (desc && typeof desc.value === "function") {
|
|
1381
|
+
methodKeys.add(name);
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
const entry = {
|
|
1385
|
+
classRef,
|
|
1386
|
+
inst,
|
|
1387
|
+
methodKeys,
|
|
1388
|
+
pendingSets: []
|
|
1389
|
+
};
|
|
1390
|
+
this.registry.set(classRef, entry);
|
|
1391
|
+
if (provideKey) this.registry.set(provideKey, entry);
|
|
1392
|
+
this.loadSeq.push(entry);
|
|
1393
|
+
if (options?.provide) {
|
|
1394
|
+
const prop = options.provide;
|
|
1395
|
+
const step = (ctx) => {
|
|
1396
|
+
Object.defineProperty(ctx, prop, {
|
|
1397
|
+
enumerable: true,
|
|
1398
|
+
configurable: true,
|
|
1399
|
+
get: () => {
|
|
1400
|
+
const currentEntry = ctx.registry.get(classRef);
|
|
1401
|
+
return wrapMaybePromise(currentEntry?.inst, { methodKeys });
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
};
|
|
1405
|
+
step(this);
|
|
1406
|
+
this.objectSteps.push(step);
|
|
1407
|
+
}
|
|
1408
|
+
if (options?.merge?.length) {
|
|
1409
|
+
for (const key of options.merge) {
|
|
1410
|
+
const desc = getMethodDescriptor(cls, key);
|
|
1411
|
+
const isMethod = !!desc && typeof desc.value === "function";
|
|
1412
|
+
const step = (ctx) => {
|
|
1413
|
+
if (isMethod) {
|
|
1414
|
+
Object.defineProperty(ctx, key, {
|
|
1415
|
+
enumerable: true,
|
|
1416
|
+
configurable: true,
|
|
1417
|
+
get: () => {
|
|
1418
|
+
const currentEntry = ctx.registry.get(classRef);
|
|
1419
|
+
const currentInst = currentEntry?.inst;
|
|
1420
|
+
if (isPromiseLike(currentInst))
|
|
1421
|
+
return createAsyncMethod(currentInst, key);
|
|
1422
|
+
const fn = currentInst?.[key];
|
|
1423
|
+
return typeof fn === "function" ? fn.bind(currentInst) : fn;
|
|
1424
|
+
}
|
|
1425
|
+
});
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
Object.defineProperty(ctx, key, {
|
|
1429
|
+
enumerable: true,
|
|
1430
|
+
configurable: true,
|
|
1431
|
+
get: () => {
|
|
1432
|
+
const currentEntry = ctx.registry.get(classRef);
|
|
1433
|
+
const target = wrapMaybePromise(currentEntry?.inst);
|
|
1434
|
+
return target?.[key];
|
|
1435
|
+
},
|
|
1436
|
+
set: (value) => {
|
|
1437
|
+
const currentEntry = ctx.registry.get(classRef);
|
|
1438
|
+
if (!currentEntry) return;
|
|
1439
|
+
if (!isPromiseLike(currentEntry.inst)) {
|
|
1440
|
+
currentEntry.inst[key] = value;
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
const state = trackPromise(currentEntry.inst);
|
|
1444
|
+
if (state.status === "fulfilled") {
|
|
1445
|
+
currentEntry.inst = state.value;
|
|
1446
|
+
flushPendingSets(currentEntry);
|
|
1447
|
+
currentEntry.inst[key] = value;
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
if (state.status === "rejected") throw state.error;
|
|
1451
|
+
currentEntry.pendingSets.push({ key, value });
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
};
|
|
1455
|
+
step(this);
|
|
1456
|
+
this.objectSteps.push(step);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
return this;
|
|
1460
|
+
}
|
|
1461
|
+
get(cls) {
|
|
1462
|
+
const key = cls;
|
|
1463
|
+
if (!this.registry.has(key)) {
|
|
1464
|
+
throw new Error(`Service not provided: ${cls.name}`);
|
|
1465
|
+
}
|
|
1466
|
+
const entry = this.registry.get(key);
|
|
1467
|
+
const inst = entry.inst;
|
|
1468
|
+
if (isPromiseLike(inst)) {
|
|
1469
|
+
const state = trackPromise(inst);
|
|
1470
|
+
if (state.status === "fulfilled") {
|
|
1471
|
+
entry.inst = state.value;
|
|
1472
|
+
flushPendingSets(entry);
|
|
1473
|
+
return state.value;
|
|
1474
|
+
}
|
|
1475
|
+
if (state.status === "rejected") throw state.error;
|
|
1476
|
+
return wrapMaybePromise(inst, {
|
|
1477
|
+
methodKeys: entry.methodKeys
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
flushPendingSets(entry);
|
|
1481
|
+
return inst;
|
|
1482
|
+
}
|
|
1483
|
+
async getAsync(cls) {
|
|
1484
|
+
const key = cls;
|
|
1485
|
+
if (!this.registry.has(key)) {
|
|
1486
|
+
throw new Error(`Service not provided: ${cls.name}`);
|
|
1487
|
+
}
|
|
1488
|
+
const entry = this.registry.get(key);
|
|
1489
|
+
const resolved = await resolveEntryIfNeeded(entry);
|
|
1490
|
+
return resolved;
|
|
1491
|
+
}
|
|
1492
|
+
use(...ctxes) {
|
|
1493
|
+
for (const ctx of ctxes) {
|
|
1494
|
+
const other = ctx;
|
|
1495
|
+
const entryMap = /* @__PURE__ */ new Map();
|
|
1496
|
+
if (Array.isArray(other?.loadSeq)) {
|
|
1497
|
+
const copiedSeq = other.loadSeq.map((item) => ({
|
|
1498
|
+
...item,
|
|
1499
|
+
methodKeys: new Set(item.methodKeys ?? []),
|
|
1500
|
+
pendingSets: [...item.pendingSets ?? []]
|
|
1501
|
+
}));
|
|
1502
|
+
other.loadSeq.forEach((item, index) => {
|
|
1503
|
+
entryMap.set(item, copiedSeq[index]);
|
|
1504
|
+
});
|
|
1505
|
+
this.loadSeq.push(...copiedSeq);
|
|
1506
|
+
}
|
|
1507
|
+
if (other?.registry instanceof Map) {
|
|
1508
|
+
for (const [key, value] of other.registry.entries()) {
|
|
1509
|
+
this.registry.set(key, entryMap.get(value) ?? value);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
if (Array.isArray(other?.objectSteps)) {
|
|
1513
|
+
this.objectSteps.push(...other.objectSteps);
|
|
1514
|
+
for (const step of other.objectSteps) {
|
|
1515
|
+
step(this);
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
return this;
|
|
1520
|
+
}
|
|
1521
|
+
define() {
|
|
1522
|
+
return this;
|
|
1523
|
+
}
|
|
1524
|
+
async start() {
|
|
1525
|
+
for (const entry of this.loadSeq) {
|
|
1526
|
+
await resolveEntryIfNeeded(entry);
|
|
1527
|
+
}
|
|
1528
|
+
for (const entry of this.loadSeq) {
|
|
1529
|
+
const inst = entry.inst;
|
|
1530
|
+
if (inst && typeof inst.init === "function") {
|
|
1531
|
+
await inst.init();
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
return this;
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1537
|
+
var createAppContext = () => new AppContextCore();
|
|
1538
|
+
|
|
1539
|
+
// src/app-context/app-service-base.ts
|
|
1540
|
+
var AppServiceBase = class {
|
|
1541
|
+
constructor(ctx, ...args) {
|
|
1542
|
+
this.ctx = ctx;
|
|
1543
|
+
}
|
|
1544
|
+
async init() {
|
|
1545
|
+
}
|
|
1546
|
+
};
|
|
1263
1547
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1264
1548
|
0 && (module.exports = {
|
|
1265
1549
|
AbortedError,
|
|
1550
|
+
AppContextCore,
|
|
1551
|
+
AppServiceBase,
|
|
1552
|
+
DUAL_PENDING,
|
|
1266
1553
|
DynamicMiddlewareDispatcher,
|
|
1267
1554
|
I18n,
|
|
1268
1555
|
I18nLookupMiddleware,
|
|
@@ -1273,11 +1560,13 @@ var makeArray = (value) => {
|
|
|
1273
1560
|
WF_NODE,
|
|
1274
1561
|
WorkflowDispatcher,
|
|
1275
1562
|
abortable,
|
|
1563
|
+
createAppContext,
|
|
1276
1564
|
createI18nLookupMiddleware,
|
|
1277
1565
|
dualizeAny,
|
|
1278
1566
|
makeArray,
|
|
1279
1567
|
observeDiff,
|
|
1280
1568
|
patchStringInObject,
|
|
1569
|
+
throwDualPending,
|
|
1281
1570
|
workflow
|
|
1282
1571
|
});
|
|
1283
1572
|
//# sourceMappingURL=index.cjs.map
|