@native-marketing/sdk 0.3.6 → 0.3.7

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/http.js CHANGED
@@ -66,31 +66,6 @@ function guardHttpMethods(client, validate) {
66
66
  });
67
67
  }
68
68
 
69
- // packages/api-client/src/client.ts
70
- function createContentFactoryClient(options = {}) {
71
- const baseUrl = options.baseUrl ?? "/api/v1";
72
- const policy = httpRequestPolicy(
73
- baseUrl,
74
- options.fetch ?? ((request) => globalThis.fetch(request))
75
- );
76
- const client = createClient({
77
- baseUrl,
78
- credentials: "include",
79
- redirect: "error",
80
- fetch: policy.fetch
81
- });
82
- client.use({
83
- onRequest({ request }) {
84
- if (!["POST", "DELETE"].includes(request.method) || request.body !== null) return request;
85
- const headers = new Headers(request.headers);
86
- headers.set("content-type", "application/json");
87
- headers.delete("content-length");
88
- return new Request(request, { headers, body: "{}" });
89
- }
90
- });
91
- return guardHttpMethods(client, policy.validateInit);
92
- }
93
-
94
69
  // packages/contracts/src/business-code.ts
95
70
  import { z } from "zod";
96
71
  var businessCodeKindSchema = z.enum([
@@ -686,6 +661,175 @@ function readingDocument(content) {
686
661
  return { body, title };
687
662
  }
688
663
 
664
+ // packages/contracts/src/client-lifecycle.ts
665
+ import { z as z5 } from "zod";
666
+
667
+ // packages/contracts/src/generated/client-release.ts
668
+ var nativeClientRelease = {
669
+ schemaVersion: 1,
670
+ product: "native-marketing",
671
+ version: "0.3.7",
672
+ packages: {
673
+ sdk: "@native-marketing/sdk",
674
+ cli: "@native-marketing/cli"
675
+ },
676
+ contractVersion: 1,
677
+ minimumClientVersion: "0.3.6",
678
+ apiMajor: 1,
679
+ nodeMajor: 24,
680
+ changes: [
681
+ "Unified SDK, CLI and MCP release discovery and compatibility checks.",
682
+ "Configurable CLI update notifications, pins and compatible automatic updates.",
683
+ "Upgrade verification and explicit continuation without replaying business commands."
684
+ ]
685
+ };
686
+
687
+ // packages/contracts/src/client-lifecycle.ts
688
+ var releaseVersionSchema = z5.string().max(128).regex(
689
+ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/
690
+ );
691
+ var clientIdentitySchema = z5.object({
692
+ version: releaseVersionSchema,
693
+ contractVersion: z5.number().int().positive(),
694
+ apiMajor: z5.number().int().positive()
695
+ });
696
+ var clientReleaseSchema = z5.object({
697
+ schemaVersion: z5.literal(1),
698
+ product: z5.literal("native-marketing"),
699
+ version: releaseVersionSchema,
700
+ packages: z5.object({
701
+ sdk: z5.literal("@native-marketing/sdk"),
702
+ cli: z5.literal("@native-marketing/cli")
703
+ }),
704
+ contractVersion: z5.number().int().positive(),
705
+ minimumClientVersion: releaseVersionSchema,
706
+ apiMajor: z5.number().int().positive(),
707
+ nodeMajor: z5.number().int().positive(),
708
+ changes: z5.array(z5.string().min(1).max(240)).max(8).default([])
709
+ });
710
+ var updatePolicySchema = z5.object({
711
+ mode: z5.enum(["off", "notify", "auto"]).default("notify"),
712
+ channel: z5.enum(["latest", "next", "beta"]).default("latest"),
713
+ pin: releaseVersionSchema.nullable().default(null),
714
+ intervalHours: z5.number().int().min(1).max(168).default(24)
715
+ }).strict();
716
+ var defaultUpdatePolicy = updatePolicySchema.parse({});
717
+ function compareReleaseVersions(left, right) {
718
+ const parse = (raw) => releaseVersionSchema.parse(raw).split("+")[0].split(/-(.*)/s);
719
+ const a = parse(left), b = parse(right);
720
+ const numbers = (x, y) => BigInt(x) < BigInt(y) ? -1 : BigInt(x) > BigInt(y) ? 1 : 0;
721
+ const ac = a[0].split("."), bc = b[0].split(".");
722
+ for (let i = 0; i < 3; i++) {
723
+ const order = numbers(ac[i], bc[i]);
724
+ if (order) return order;
725
+ }
726
+ if (a[1] === b[1]) return 0;
727
+ if (!a[1] || !b[1]) return a[1] ? -1 : 1;
728
+ const ap = a[1].split("."), bp = b[1].split(".");
729
+ for (let i = 0; i < Math.max(ap.length, bp.length); i++) {
730
+ const x = ap[i], y = bp[i];
731
+ if (x === void 0 || y === void 0) return x === void 0 ? -1 : 1;
732
+ if (x === y) continue;
733
+ const xn = /^\d+$/.test(x), yn = /^\d+$/.test(y);
734
+ return xn && yn ? numbers(x, y) : xn !== yn ? xn ? -1 : 1 : x < y ? -1 : 1;
735
+ }
736
+ return 0;
737
+ }
738
+ function assessNativeCompatibility(client, server) {
739
+ client = clientIdentitySchema.parse(client);
740
+ const result = (status, reason) => ({ status, reason, client, server: server ?? null });
741
+ if (!server) return result("UNKNOWN", "SERVER_METADATA_UNAVAILABLE");
742
+ server = clientReleaseSchema.parse(server);
743
+ if (client.contractVersion !== server.contractVersion)
744
+ return result("INCOMPATIBLE", "CONTRACT_MISMATCH");
745
+ if (client.apiMajor !== server.apiMajor) return result("INCOMPATIBLE", "API_MISMATCH");
746
+ if (compareReleaseVersions(client.version, server.minimumClientVersion) < 0)
747
+ return result("INCOMPATIBLE", "CLIENT_TOO_OLD");
748
+ return compareReleaseVersions(client.version, server.version) < 0 ? result("UPGRADE_RECOMMENDED", "NEWER_CLIENT_AVAILABLE") : result("COMPATIBLE", "CURRENT");
749
+ }
750
+
751
+ // packages/contracts/src/client-update-policy.ts
752
+ import { z as z6 } from "zod";
753
+ var registryReleaseSchema = z6.object({
754
+ name: z6.enum(["@native-marketing/sdk", "@native-marketing/cli"]),
755
+ version: releaseVersionSchema,
756
+ deprecated: z6.string().optional(),
757
+ nativeMarketing: z6.object({
758
+ contractVersion: z6.number().int().positive(),
759
+ apiMajor: z6.number().int().positive(),
760
+ nodeMajor: z6.number().int().positive(),
761
+ changes: z6.array(z6.string().min(1).max(240)).max(8).optional()
762
+ }).optional(),
763
+ dist: z6.object({
764
+ integrity: z6.string().max(512).regex(/^sha512-[A-Za-z0-9+/]{86}==$/)
765
+ })
766
+ });
767
+ var clientUpdateStateSchema = z6.object({
768
+ schemaVersion: z6.literal(1),
769
+ policy: updatePolicySchema,
770
+ lastCheck: z6.object({
771
+ at: z6.number().int().nonnegative(),
772
+ selector: z6.string().max(160),
773
+ target: registryReleaseSchema
774
+ }).strict().optional(),
775
+ lastAttempt: z6.object({ at: z6.number().int().nonnegative(), selector: z6.string().max(160) }).strict().optional()
776
+ }).strict();
777
+ function planNativeUpdate(input) {
778
+ const target = registryReleaseSchema.parse(input.target);
779
+ const current = releaseVersionSchema.parse(input.currentVersion ?? nativeClientRelease.version);
780
+ const policy = updatePolicySchema.parse(input.policy ?? {});
781
+ const spec = `${target.name}@${target.version}`;
782
+ const cli = target.name === nativeClientRelease.packages.cli;
783
+ const result = (status, reason, eligible = false) => ({
784
+ package: target.name,
785
+ currentVersion: current,
786
+ targetVersion: target.version,
787
+ status,
788
+ reason,
789
+ eligibleForAutoUpdate: eligible,
790
+ policy,
791
+ commands: {
792
+ npm: [
793
+ "npm",
794
+ "install",
795
+ ...cli ? ["--global"] : ["--save-exact"],
796
+ spec,
797
+ "--ignore-scripts",
798
+ "--registry=https://registry.npmjs.org/",
799
+ "--@native-marketing:registry=https://registry.npmjs.org/"
800
+ ],
801
+ pnpm: ["pnpm", "add", ...cli ? ["--global"] : ["--save-exact"], spec, "--ignore-scripts"],
802
+ yarn: cli ? null : ["yarn", "add", "--exact", spec]
803
+ }
804
+ });
805
+ if (policy.pin && policy.pin !== target.version) return result("BLOCKED", "PIN_MISMATCH");
806
+ if (!policy.pin && policy.channel === "latest" && target.version.split("+")[0].includes("-"))
807
+ return result("BLOCKED", "CHANNEL_MISMATCH");
808
+ const order = compareReleaseVersions(target.version, current);
809
+ if (order < 0) return result("BLOCKED", "DOWNGRADE_FORBIDDEN");
810
+ if (target.deprecated !== void 0) return result("BLOCKED", "DEPRECATED");
811
+ if (!target.nativeMarketing) return result("BLOCKED", "METADATA_UNAVAILABLE");
812
+ const metadata = target.nativeMarketing;
813
+ if (metadata.nodeMajor !== (input.nodeMajor ?? nativeClientRelease.nodeMajor))
814
+ return result("BLOCKED", "NODE_MISMATCH");
815
+ if (metadata.contractVersion !== nativeClientRelease.contractVersion || metadata.apiMajor !== nativeClientRelease.apiMajor)
816
+ return result("BLOCKED", "CONTRACT_MISMATCH");
817
+ if (input.server && assessNativeCompatibility(
818
+ {
819
+ version: target.version,
820
+ contractVersion: metadata.contractVersion,
821
+ apiMajor: metadata.apiMajor
822
+ },
823
+ input.server
824
+ ).status === "INCOMPATIBLE")
825
+ return result("BLOCKED", "SERVER_INCOMPATIBLE");
826
+ if (order === 0) return result("CURRENT", "CURRENT");
827
+ const from = current.split(/[.+-]/), to = target.version.split(/[.+-]/);
828
+ const compatibleLine = from[0] === to[0] && (from[0] !== "0" || from[1] === to[1]);
829
+ const stable = !current.split("+")[0].includes("-") && !target.version.split("+")[0].includes("-");
830
+ return compatibleLine && stable ? result("UPDATE_AVAILABLE", "COMPATIBLE_UPDATE", true) : result("UPDATE_AVAILABLE", "REVIEW_REQUIRED");
831
+ }
832
+
689
833
  // packages/api-client/src/errors.ts
690
834
  var ApiClientError = class extends Error {
691
835
  constructor(status, code, message, requestId) {
@@ -710,6 +854,102 @@ function requireApiData(result) {
710
854
  );
711
855
  }
712
856
 
857
+ // packages/api-client/src/client-version.ts
858
+ function getNativeClientVersion() {
859
+ return clientReleaseSchema.parse(nativeClientRelease);
860
+ }
861
+ async function checkNativeHttpVersion(options = {}) {
862
+ const base = options.baseUrl ?? "/api/v1";
863
+ const policy = httpRequestPolicy(base, options.fetch ?? ((request) => fetch(request)));
864
+ const timeout = options.timeoutMs ?? 5e3;
865
+ if (!Number.isInteger(timeout) || timeout < 100 || timeout > 12e4)
866
+ throw new TypeError("Timeout must be 100\u2013120000 milliseconds.");
867
+ const endpoint = new URL(
868
+ `${base.replace(/\/+$/, "")}/client-release`,
869
+ globalThis.location?.origin
870
+ );
871
+ let server;
872
+ try {
873
+ const response = await policy.fetch(
874
+ new Request(endpoint, {
875
+ credentials: "omit",
876
+ redirect: "error",
877
+ signal: AbortSignal.timeout(timeout)
878
+ })
879
+ );
880
+ if (response.status !== 404) {
881
+ if (!response.ok || !response.body) throw new Error();
882
+ const reader = response.body.getReader();
883
+ const decoder = new TextDecoder("utf-8", { fatal: true });
884
+ let size = 0, raw = "";
885
+ try {
886
+ for (; ; ) {
887
+ const { value, done } = await reader.read();
888
+ if (done) break;
889
+ size += value.byteLength;
890
+ if (size > 32 * 1024) throw new Error();
891
+ raw += decoder.decode(value, { stream: true });
892
+ }
893
+ raw += decoder.decode();
894
+ } finally {
895
+ await reader.cancel().catch(() => void 0);
896
+ reader.releaseLock();
897
+ }
898
+ server = clientReleaseSchema.parse(JSON.parse(raw));
899
+ }
900
+ } catch {
901
+ throw new ApiClientError(
902
+ 0,
903
+ "VERSION_CHECK_UNAVAILABLE",
904
+ "Cannot verify the configured service release."
905
+ );
906
+ }
907
+ const compatibility = assessNativeCompatibility(nativeClientRelease, server);
908
+ if (compatibility.status === "INCOMPATIBLE" || options.requireCompatibility && compatibility.status === "UNKNOWN")
909
+ throw new ApiClientError(
910
+ 0,
911
+ "CLIENT_INCOMPATIBLE",
912
+ "The client cannot confirm compatibility with this service."
913
+ );
914
+ return { client: getNativeClientVersion(), compatibility };
915
+ }
916
+
917
+ // packages/api-client/src/client.ts
918
+ function createContentFactoryClient(options = {}) {
919
+ const baseUrl = options.baseUrl ?? "/api/v1";
920
+ const policy = httpRequestPolicy(
921
+ baseUrl,
922
+ options.fetch ?? ((request) => globalThis.fetch(request))
923
+ );
924
+ let versionCheck;
925
+ const client = createClient({
926
+ baseUrl,
927
+ credentials: "include",
928
+ redirect: "error",
929
+ fetch: async (request) => {
930
+ if (options.compatibility) {
931
+ versionCheck ??= checkNativeHttpVersion({
932
+ baseUrl,
933
+ ...options.fetch ? { fetch: options.fetch } : {},
934
+ requireCompatibility: options.compatibility === "require"
935
+ });
936
+ await versionCheck;
937
+ }
938
+ return policy.fetch(request);
939
+ }
940
+ });
941
+ client.use({
942
+ onRequest({ request }) {
943
+ if (!["POST", "DELETE"].includes(request.method) || request.body !== null) return request;
944
+ const headers = new Headers(request.headers);
945
+ headers.set("content-type", "application/json");
946
+ headers.delete("content-length");
947
+ return new Request(request, { headers, body: "{}" });
948
+ }
949
+ });
950
+ return guardHttpMethods(client, policy.validateInit);
951
+ }
952
+
713
953
  // packages/api-client/src/personal-survey.ts
714
954
  var personalSurveyInputLimits = {
715
955
  professionalIdentity: 2e3,
@@ -1320,9 +1560,13 @@ function suggestProjectKey(name) {
1320
1560
  }
1321
1561
  export {
1322
1562
  ApiClientError,
1563
+ assessNativeCompatibility,
1564
+ checkNativeHttpVersion,
1323
1565
  contentProgramInputLimits,
1324
1566
  createContentFactoryClient,
1567
+ defaultUpdatePolicy,
1325
1568
  distributionDestinationInputLimits,
1569
+ getNativeClientVersion,
1326
1570
  humanActionInputLimits,
1327
1571
  matchesHumanRequirementMedia,
1328
1572
  mediaInputLimits,
@@ -1330,6 +1574,7 @@ export {
1330
1574
  personalIpDefinitionInputLimits,
1331
1575
  personalSurveyInputLimits,
1332
1576
  personalSurveyToResponses,
1577
+ planNativeUpdate,
1333
1578
  programActivationRequirements,
1334
1579
  programGoalMetricDefinitions,
1335
1580
  publicationInputLimits,