@namiml/sdk-core 3.4.4-dev.202607072107 → 3.4.4-dev.202607072357
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 +71 -7
- package/dist/index.d.ts +15 -0
- package/dist/index.mjs +71 -7
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -98,7 +98,7 @@ const {
|
|
|
98
98
|
// version — stamped by scripts/version.sh
|
|
99
99
|
NAMI_SDK_VERSION: exports.NAMI_SDK_VERSION = "3.4.4",
|
|
100
100
|
// full package version including dev suffix — stamped by scripts/version.sh
|
|
101
|
-
NAMI_SDK_PACKAGE_VERSION: exports.NAMI_SDK_PACKAGE_VERSION = "3.4.4-dev.
|
|
101
|
+
NAMI_SDK_PACKAGE_VERSION: exports.NAMI_SDK_PACKAGE_VERSION = "3.4.4-dev.202607072357",
|
|
102
102
|
// environments
|
|
103
103
|
PRODUCTION: exports.PRODUCTION = "production", DEVELOPMENT: exports.DEVELOPMENT = "development",
|
|
104
104
|
// error messages
|
|
@@ -61891,6 +61891,13 @@ const NamiHandoffTag = {
|
|
|
61891
61891
|
BuySku: 'buysku',
|
|
61892
61892
|
UserData: 'userdata',
|
|
61893
61893
|
};
|
|
61894
|
+
/**
|
|
61895
|
+
* True iff `tag` is a value of the customer-facing `NamiHandoffTag` vocabulary.
|
|
61896
|
+
* Unknown tags are still delivered (pass-through) — this only drives a warning.
|
|
61897
|
+
*/
|
|
61898
|
+
function isKnownHandoffTag(tag) {
|
|
61899
|
+
return Object.values(NamiHandoffTag).includes(tag);
|
|
61900
|
+
}
|
|
61894
61901
|
/**
|
|
61895
61902
|
* Permission types reportable through a handoff outcome.
|
|
61896
61903
|
*
|
|
@@ -63988,6 +63995,8 @@ function validateForm(validators, formStates) {
|
|
|
63988
63995
|
return errors;
|
|
63989
63996
|
}
|
|
63990
63997
|
|
|
63998
|
+
/** Form field key convention for grouped handoffs: `<tag>::<payloadKey>`. */
|
|
63999
|
+
const HANDOFF_GROUP_KEY = /^([^:]+)::(.+)$/;
|
|
63991
64000
|
class BasicNamiFlow {
|
|
63992
64001
|
constructor(flowObject = {}) {
|
|
63993
64002
|
this.id = flowObject.id ?? '';
|
|
@@ -64756,13 +64765,25 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
64756
64765
|
logger.warn("No formStates available for handoff sequence");
|
|
64757
64766
|
return;
|
|
64758
64767
|
}
|
|
64759
|
-
const keys = Object.keys(formStates)
|
|
64768
|
+
const keys = Object.keys(formStates);
|
|
64760
64769
|
if (keys.length === 0) {
|
|
64761
64770
|
logger.warn("formStates is empty, no handoffs to perform");
|
|
64762
64771
|
return;
|
|
64763
64772
|
}
|
|
64764
|
-
//
|
|
64765
|
-
|
|
64773
|
+
// Grouped path: at least one field uses the `tag::field` convention.
|
|
64774
|
+
if (keys.some((k) => HANDOFF_GROUP_KEY.test(k))) {
|
|
64775
|
+
const groups = this.buildHandoffGroups(formStates);
|
|
64776
|
+
if (groups.length === 0) {
|
|
64777
|
+
logger.info("No handoff groups after grouping");
|
|
64778
|
+
this.manager.resume();
|
|
64779
|
+
return;
|
|
64780
|
+
}
|
|
64781
|
+
this.activeHandoffSequence = { groups };
|
|
64782
|
+
this.resumeNextHandoff();
|
|
64783
|
+
return;
|
|
64784
|
+
}
|
|
64785
|
+
// Legacy path (unchanged): one handoff per true key, tag = field name.
|
|
64786
|
+
const eligibleKeys = keys.sort().filter((k) => formStates[k] === true);
|
|
64766
64787
|
if (eligibleKeys.length === 0) {
|
|
64767
64788
|
logger.info("No eligible handoff keys after filtering");
|
|
64768
64789
|
this.manager.resume();
|
|
@@ -64774,6 +64795,34 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
64774
64795
|
};
|
|
64775
64796
|
this.resumeNextHandoff();
|
|
64776
64797
|
}
|
|
64798
|
+
/**
|
|
64799
|
+
* Reduce a flat `formStates` map into one bucket per distinct handoff tag,
|
|
64800
|
+
* using the `<tag>::<payloadKey>` field-key convention. Insertion order is
|
|
64801
|
+
* preserved (group order = first-appearance). Reserved-prefixed tags are
|
|
64802
|
+
* skipped so they never reach the host handler (NAM-1556). A group is kept
|
|
64803
|
+
* only if at least one of its fields is `true` (a permission the user
|
|
64804
|
+
* declined is not handed off); a kept group's payload rides verbatim,
|
|
64805
|
+
* including its `false` fields.
|
|
64806
|
+
*/
|
|
64807
|
+
buildHandoffGroups(formStates) {
|
|
64808
|
+
const buckets = new Map();
|
|
64809
|
+
for (const key of Object.keys(formStates)) {
|
|
64810
|
+
const match = key.match(HANDOFF_GROUP_KEY);
|
|
64811
|
+
if (!match)
|
|
64812
|
+
continue;
|
|
64813
|
+
const [, tag, field] = match;
|
|
64814
|
+
if (tag.startsWith(RESERVED_HANDOFF_TAG_PREFIX)) {
|
|
64815
|
+
logger.warn(`Ignoring reserved handoff group tag '${tag}'`);
|
|
64816
|
+
continue;
|
|
64817
|
+
}
|
|
64818
|
+
if (!buckets.has(tag))
|
|
64819
|
+
buckets.set(tag, {});
|
|
64820
|
+
buckets.get(tag)[field] = formStates[key];
|
|
64821
|
+
}
|
|
64822
|
+
return Array.from(buckets, ([tag, data]) => ({ tag, data }))
|
|
64823
|
+
.filter((group) => Object.values(group.data).some((value) => value === true))
|
|
64824
|
+
.sort((a, b) => a.tag.localeCompare(b.tag));
|
|
64825
|
+
}
|
|
64777
64826
|
resumeNextHandoff() {
|
|
64778
64827
|
const sequence = this.activeHandoffSequence;
|
|
64779
64828
|
if (!sequence) {
|
|
@@ -64781,6 +64830,24 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
64781
64830
|
this.manager.resume();
|
|
64782
64831
|
return;
|
|
64783
64832
|
}
|
|
64833
|
+
// Grouped path.
|
|
64834
|
+
if ("groups" in sequence) {
|
|
64835
|
+
if (sequence.groups.length === 0) {
|
|
64836
|
+
logger.info("All handoffs in the sequence are complete");
|
|
64837
|
+
this.activeHandoffSequence = null;
|
|
64838
|
+
this.manager.resume();
|
|
64839
|
+
return;
|
|
64840
|
+
}
|
|
64841
|
+
const next = sequence.groups.shift(); // safe: length > 0
|
|
64842
|
+
if (!isKnownHandoffTag(next.tag)) {
|
|
64843
|
+
logger.warn(`handoff group tag '${next.tag}' is outside the NamiHandoffTag vocabulary — passing through`);
|
|
64844
|
+
}
|
|
64845
|
+
this.activeHandoffSequence = sequence; // persist mutated groups
|
|
64846
|
+
logger.debug(`Starting grouped handoff for '${next.tag}' → ${JSON.stringify(next.data)}`);
|
|
64847
|
+
this.manager.deliverHandoff(next.tag, next.data);
|
|
64848
|
+
return;
|
|
64849
|
+
}
|
|
64850
|
+
// Legacy path (unchanged).
|
|
64784
64851
|
if (sequence.remainingKeys.length === 0) {
|
|
64785
64852
|
logger.info("All handoffs in the sequence are complete");
|
|
64786
64853
|
this.activeHandoffSequence = null;
|
|
@@ -64790,10 +64857,7 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
64790
64857
|
const nextKey = sequence.remainingKeys.shift(); // safe: length > 0
|
|
64791
64858
|
const value = sequence.formStates[nextKey];
|
|
64792
64859
|
logger.debug(`Starting handoff for ${nextKey} → ${String(value)}`);
|
|
64793
|
-
// persist updated sequence (remainingKeys mutated)
|
|
64794
64860
|
this.activeHandoffSequence = sequence;
|
|
64795
|
-
// Route through the manager's single delivery point so v2 handlers get
|
|
64796
|
-
// a working complete() for sequence-key handoffs too.
|
|
64797
64861
|
this.manager.deliverHandoff(`${nextKey}`, undefined);
|
|
64798
64862
|
}
|
|
64799
64863
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2249,6 +2249,11 @@ declare class NamiFlow extends BasicNamiFlow {
|
|
|
2249
2249
|
activeHandoffSequence: {
|
|
2250
2250
|
formStates: Record<string, boolean | string>;
|
|
2251
2251
|
remainingKeys: string[];
|
|
2252
|
+
} | {
|
|
2253
|
+
groups: Array<{
|
|
2254
|
+
tag: string;
|
|
2255
|
+
data: Record<string, boolean | string>;
|
|
2256
|
+
}>;
|
|
2252
2257
|
} | null;
|
|
2253
2258
|
currentScreenState: TPaywallContext | null;
|
|
2254
2259
|
isPaused: boolean;
|
|
@@ -2357,6 +2362,16 @@ declare class NamiFlow extends BasicNamiFlow {
|
|
|
2357
2362
|
*/
|
|
2358
2363
|
buildUserDataEnvelope(formId: string): NamiUserDataEnvelope;
|
|
2359
2364
|
flowHandoffFormSequence(): void;
|
|
2365
|
+
/**
|
|
2366
|
+
* Reduce a flat `formStates` map into one bucket per distinct handoff tag,
|
|
2367
|
+
* using the `<tag>::<payloadKey>` field-key convention. Insertion order is
|
|
2368
|
+
* preserved (group order = first-appearance). Reserved-prefixed tags are
|
|
2369
|
+
* skipped so they never reach the host handler (NAM-1556). A group is kept
|
|
2370
|
+
* only if at least one of its fields is `true` (a permission the user
|
|
2371
|
+
* declined is not handed off); a kept group's payload rides verbatim,
|
|
2372
|
+
* including its `false` fields.
|
|
2373
|
+
*/
|
|
2374
|
+
private buildHandoffGroups;
|
|
2360
2375
|
resumeNextHandoff(): void;
|
|
2361
2376
|
}
|
|
2362
2377
|
|
package/dist/index.mjs
CHANGED
|
@@ -96,7 +96,7 @@ const {
|
|
|
96
96
|
// version — stamped by scripts/version.sh
|
|
97
97
|
NAMI_SDK_VERSION = "3.4.4",
|
|
98
98
|
// full package version including dev suffix — stamped by scripts/version.sh
|
|
99
|
-
NAMI_SDK_PACKAGE_VERSION = "3.4.4-dev.
|
|
99
|
+
NAMI_SDK_PACKAGE_VERSION = "3.4.4-dev.202607072357",
|
|
100
100
|
// environments
|
|
101
101
|
PRODUCTION = "production", DEVELOPMENT = "development",
|
|
102
102
|
// error messages
|
|
@@ -61889,6 +61889,13 @@ const NamiHandoffTag = {
|
|
|
61889
61889
|
BuySku: 'buysku',
|
|
61890
61890
|
UserData: 'userdata',
|
|
61891
61891
|
};
|
|
61892
|
+
/**
|
|
61893
|
+
* True iff `tag` is a value of the customer-facing `NamiHandoffTag` vocabulary.
|
|
61894
|
+
* Unknown tags are still delivered (pass-through) — this only drives a warning.
|
|
61895
|
+
*/
|
|
61896
|
+
function isKnownHandoffTag(tag) {
|
|
61897
|
+
return Object.values(NamiHandoffTag).includes(tag);
|
|
61898
|
+
}
|
|
61892
61899
|
/**
|
|
61893
61900
|
* Permission types reportable through a handoff outcome.
|
|
61894
61901
|
*
|
|
@@ -63986,6 +63993,8 @@ function validateForm(validators, formStates) {
|
|
|
63986
63993
|
return errors;
|
|
63987
63994
|
}
|
|
63988
63995
|
|
|
63996
|
+
/** Form field key convention for grouped handoffs: `<tag>::<payloadKey>`. */
|
|
63997
|
+
const HANDOFF_GROUP_KEY = /^([^:]+)::(.+)$/;
|
|
63989
63998
|
class BasicNamiFlow {
|
|
63990
63999
|
constructor(flowObject = {}) {
|
|
63991
64000
|
this.id = flowObject.id ?? '';
|
|
@@ -64754,13 +64763,25 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
64754
64763
|
logger.warn("No formStates available for handoff sequence");
|
|
64755
64764
|
return;
|
|
64756
64765
|
}
|
|
64757
|
-
const keys = Object.keys(formStates)
|
|
64766
|
+
const keys = Object.keys(formStates);
|
|
64758
64767
|
if (keys.length === 0) {
|
|
64759
64768
|
logger.warn("formStates is empty, no handoffs to perform");
|
|
64760
64769
|
return;
|
|
64761
64770
|
}
|
|
64762
|
-
//
|
|
64763
|
-
|
|
64771
|
+
// Grouped path: at least one field uses the `tag::field` convention.
|
|
64772
|
+
if (keys.some((k) => HANDOFF_GROUP_KEY.test(k))) {
|
|
64773
|
+
const groups = this.buildHandoffGroups(formStates);
|
|
64774
|
+
if (groups.length === 0) {
|
|
64775
|
+
logger.info("No handoff groups after grouping");
|
|
64776
|
+
this.manager.resume();
|
|
64777
|
+
return;
|
|
64778
|
+
}
|
|
64779
|
+
this.activeHandoffSequence = { groups };
|
|
64780
|
+
this.resumeNextHandoff();
|
|
64781
|
+
return;
|
|
64782
|
+
}
|
|
64783
|
+
// Legacy path (unchanged): one handoff per true key, tag = field name.
|
|
64784
|
+
const eligibleKeys = keys.sort().filter((k) => formStates[k] === true);
|
|
64764
64785
|
if (eligibleKeys.length === 0) {
|
|
64765
64786
|
logger.info("No eligible handoff keys after filtering");
|
|
64766
64787
|
this.manager.resume();
|
|
@@ -64772,6 +64793,34 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
64772
64793
|
};
|
|
64773
64794
|
this.resumeNextHandoff();
|
|
64774
64795
|
}
|
|
64796
|
+
/**
|
|
64797
|
+
* Reduce a flat `formStates` map into one bucket per distinct handoff tag,
|
|
64798
|
+
* using the `<tag>::<payloadKey>` field-key convention. Insertion order is
|
|
64799
|
+
* preserved (group order = first-appearance). Reserved-prefixed tags are
|
|
64800
|
+
* skipped so they never reach the host handler (NAM-1556). A group is kept
|
|
64801
|
+
* only if at least one of its fields is `true` (a permission the user
|
|
64802
|
+
* declined is not handed off); a kept group's payload rides verbatim,
|
|
64803
|
+
* including its `false` fields.
|
|
64804
|
+
*/
|
|
64805
|
+
buildHandoffGroups(formStates) {
|
|
64806
|
+
const buckets = new Map();
|
|
64807
|
+
for (const key of Object.keys(formStates)) {
|
|
64808
|
+
const match = key.match(HANDOFF_GROUP_KEY);
|
|
64809
|
+
if (!match)
|
|
64810
|
+
continue;
|
|
64811
|
+
const [, tag, field] = match;
|
|
64812
|
+
if (tag.startsWith(RESERVED_HANDOFF_TAG_PREFIX)) {
|
|
64813
|
+
logger.warn(`Ignoring reserved handoff group tag '${tag}'`);
|
|
64814
|
+
continue;
|
|
64815
|
+
}
|
|
64816
|
+
if (!buckets.has(tag))
|
|
64817
|
+
buckets.set(tag, {});
|
|
64818
|
+
buckets.get(tag)[field] = formStates[key];
|
|
64819
|
+
}
|
|
64820
|
+
return Array.from(buckets, ([tag, data]) => ({ tag, data }))
|
|
64821
|
+
.filter((group) => Object.values(group.data).some((value) => value === true))
|
|
64822
|
+
.sort((a, b) => a.tag.localeCompare(b.tag));
|
|
64823
|
+
}
|
|
64775
64824
|
resumeNextHandoff() {
|
|
64776
64825
|
const sequence = this.activeHandoffSequence;
|
|
64777
64826
|
if (!sequence) {
|
|
@@ -64779,6 +64828,24 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
64779
64828
|
this.manager.resume();
|
|
64780
64829
|
return;
|
|
64781
64830
|
}
|
|
64831
|
+
// Grouped path.
|
|
64832
|
+
if ("groups" in sequence) {
|
|
64833
|
+
if (sequence.groups.length === 0) {
|
|
64834
|
+
logger.info("All handoffs in the sequence are complete");
|
|
64835
|
+
this.activeHandoffSequence = null;
|
|
64836
|
+
this.manager.resume();
|
|
64837
|
+
return;
|
|
64838
|
+
}
|
|
64839
|
+
const next = sequence.groups.shift(); // safe: length > 0
|
|
64840
|
+
if (!isKnownHandoffTag(next.tag)) {
|
|
64841
|
+
logger.warn(`handoff group tag '${next.tag}' is outside the NamiHandoffTag vocabulary — passing through`);
|
|
64842
|
+
}
|
|
64843
|
+
this.activeHandoffSequence = sequence; // persist mutated groups
|
|
64844
|
+
logger.debug(`Starting grouped handoff for '${next.tag}' → ${JSON.stringify(next.data)}`);
|
|
64845
|
+
this.manager.deliverHandoff(next.tag, next.data);
|
|
64846
|
+
return;
|
|
64847
|
+
}
|
|
64848
|
+
// Legacy path (unchanged).
|
|
64782
64849
|
if (sequence.remainingKeys.length === 0) {
|
|
64783
64850
|
logger.info("All handoffs in the sequence are complete");
|
|
64784
64851
|
this.activeHandoffSequence = null;
|
|
@@ -64788,10 +64855,7 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
64788
64855
|
const nextKey = sequence.remainingKeys.shift(); // safe: length > 0
|
|
64789
64856
|
const value = sequence.formStates[nextKey];
|
|
64790
64857
|
logger.debug(`Starting handoff for ${nextKey} → ${String(value)}`);
|
|
64791
|
-
// persist updated sequence (remainingKeys mutated)
|
|
64792
64858
|
this.activeHandoffSequence = sequence;
|
|
64793
|
-
// Route through the manager's single delivery point so v2 handlers get
|
|
64794
|
-
// a working complete() for sequence-key handoffs too.
|
|
64795
64859
|
this.manager.deliverHandoff(`${nextKey}`, undefined);
|
|
64796
64860
|
}
|
|
64797
64861
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@namiml/sdk-core",
|
|
3
|
-
"version": "3.4.4-dev.
|
|
3
|
+
"version": "3.4.4-dev.202607072357",
|
|
4
4
|
"description": "Platform-agnostic core for the Nami SDK — business logic, API, types, and state management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|