nfkit 1.0.20 → 1.0.22

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 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
  }
@@ -1231,11 +1247,11 @@ var observeDiff = (obj, cb) => {
1231
1247
  // src/memorize.ts
1232
1248
  var Memorize = () => {
1233
1249
  const cache = /* @__PURE__ */ new WeakMap();
1234
- const isPromiseLike = (v) => v != null && typeof v.then === "function" && typeof v.catch === "function";
1250
+ const isPromiseLike2 = (v) => v != null && typeof v.then === "function" && typeof v.catch === "function";
1235
1251
  const getOrSet = (instance, compute) => {
1236
1252
  if (cache.has(instance)) return cache.get(instance);
1237
1253
  const result = compute();
1238
- if (isPromiseLike(result)) {
1254
+ if (isPromiseLike2(result)) {
1239
1255
  const wrapped = result.catch((err) => {
1240
1256
  cache.delete(instance);
1241
1257
  throw err;
@@ -1268,9 +1284,272 @@ var Memorize = () => {
1268
1284
  var makeArray = (value) => {
1269
1285
  return Array.isArray(value) ? value : [value];
1270
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
+ };
1271
1547
  // Annotate the CommonJS export names for ESM import in node:
1272
1548
  0 && (module.exports = {
1273
1549
  AbortedError,
1550
+ AppContextCore,
1551
+ AppServiceBase,
1552
+ DUAL_PENDING,
1274
1553
  DynamicMiddlewareDispatcher,
1275
1554
  I18n,
1276
1555
  I18nLookupMiddleware,
@@ -1281,11 +1560,13 @@ var makeArray = (value) => {
1281
1560
  WF_NODE,
1282
1561
  WorkflowDispatcher,
1283
1562
  abortable,
1563
+ createAppContext,
1284
1564
  createI18nLookupMiddleware,
1285
1565
  dualizeAny,
1286
1566
  makeArray,
1287
1567
  observeDiff,
1288
1568
  patchStringInObject,
1569
+ throwDualPending,
1289
1570
  workflow
1290
1571
  });
1291
1572
  //# sourceMappingURL=index.cjs.map