@shipeasy/sdk 2.5.2 → 3.0.0
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/client/index.d.mts +18 -7
- package/dist/client/index.d.ts +18 -7
- package/dist/client/index.js +21 -8
- package/dist/client/index.mjs +21 -8
- package/dist/server/index.d.mts +18 -22
- package/dist/server/index.d.ts +18 -22
- package/dist/server/index.js +9 -19
- package/dist/server/index.mjs +9 -19
- package/package.json +1 -1
package/dist/client/index.d.mts
CHANGED
|
@@ -137,12 +137,23 @@ interface AttachDevtoolsOptions {
|
|
|
137
137
|
declare function attachDevtools(client: FlagsClientBrowser, opts?: AttachDevtoolsOptions): () => void;
|
|
138
138
|
/** Configure the singleton. Idempotent — re-calling with the same opts is a no-op. */
|
|
139
139
|
interface ShipeasyClientConfig {
|
|
140
|
-
/**
|
|
141
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Public client key — the ONLY key the browser entrypoint accepts. Authenticates
|
|
142
|
+
* /sdk/evaluate, /collect and the runtime i18n loader (/sdk/i18n/strings). Safe to
|
|
143
|
+
* expose (e.g. NEXT_PUBLIC_ env vars). This is a different key from the server key
|
|
144
|
+
* passed to `shipeasy({ serverKey })` in @shipeasy/sdk/server — never use the
|
|
145
|
+
* server key here.
|
|
146
|
+
*/
|
|
147
|
+
clientKey: string;
|
|
142
148
|
/** Override the ShipEasy CDN/edge base URL. Defaults to https://cdn.shipeasy.ai. */
|
|
143
149
|
baseUrl?: string;
|
|
144
150
|
/** Override the admin URL for the devtools overlay (dev use). */
|
|
145
151
|
adminUrl?: string;
|
|
152
|
+
/**
|
|
153
|
+
* i18n profile for the runtime string loader, e.g. "en:prod". Defaults to the
|
|
154
|
+
* profile the server recorded in window.__SE_BOOTSTRAP, then "en:prod".
|
|
155
|
+
*/
|
|
156
|
+
i18nProfile?: string;
|
|
146
157
|
/**
|
|
147
158
|
* Skip the lazy auto-identify({}) at boot. Defaults to true (auto-identify on).
|
|
148
159
|
* Turn off when the host has its own identify orchestration and wants to
|
|
@@ -158,9 +169,9 @@ interface ShipeasyClientConfig {
|
|
|
158
169
|
* Pass `false` to disable everything, or a per-group object to narrow:
|
|
159
170
|
*
|
|
160
171
|
* ```ts
|
|
161
|
-
* shipeasy({
|
|
162
|
-
* shipeasy({
|
|
163
|
-
* shipeasy({
|
|
172
|
+
* shipeasy({ clientKey, autoCollect: false }); // off
|
|
173
|
+
* shipeasy({ clientKey, autoCollect: { errors: false } }); // vitals + engagement only
|
|
174
|
+
* shipeasy({ clientKey }); // all groups on
|
|
164
175
|
* ```
|
|
165
176
|
*/
|
|
166
177
|
autoCollect?: boolean | Partial<AutoCollectGroups>;
|
|
@@ -198,8 +209,8 @@ interface BootstrapPayload {
|
|
|
198
209
|
* the killswitch is not whole-killed and the map carries per-switch state.
|
|
199
210
|
*/
|
|
200
211
|
killswitches?: Record<string, boolean | Record<string, boolean>>;
|
|
201
|
-
/**
|
|
202
|
-
|
|
212
|
+
/** i18n profile the server rendered with, so the client loader matches. No key is embedded. */
|
|
213
|
+
i18nProfile?: string;
|
|
203
214
|
apiUrl?: string;
|
|
204
215
|
/** When true, tEl() returns marker-wrapped strings for devtools label editing. */
|
|
205
216
|
editLabels?: boolean;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -137,12 +137,23 @@ interface AttachDevtoolsOptions {
|
|
|
137
137
|
declare function attachDevtools(client: FlagsClientBrowser, opts?: AttachDevtoolsOptions): () => void;
|
|
138
138
|
/** Configure the singleton. Idempotent — re-calling with the same opts is a no-op. */
|
|
139
139
|
interface ShipeasyClientConfig {
|
|
140
|
-
/**
|
|
141
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Public client key — the ONLY key the browser entrypoint accepts. Authenticates
|
|
142
|
+
* /sdk/evaluate, /collect and the runtime i18n loader (/sdk/i18n/strings). Safe to
|
|
143
|
+
* expose (e.g. NEXT_PUBLIC_ env vars). This is a different key from the server key
|
|
144
|
+
* passed to `shipeasy({ serverKey })` in @shipeasy/sdk/server — never use the
|
|
145
|
+
* server key here.
|
|
146
|
+
*/
|
|
147
|
+
clientKey: string;
|
|
142
148
|
/** Override the ShipEasy CDN/edge base URL. Defaults to https://cdn.shipeasy.ai. */
|
|
143
149
|
baseUrl?: string;
|
|
144
150
|
/** Override the admin URL for the devtools overlay (dev use). */
|
|
145
151
|
adminUrl?: string;
|
|
152
|
+
/**
|
|
153
|
+
* i18n profile for the runtime string loader, e.g. "en:prod". Defaults to the
|
|
154
|
+
* profile the server recorded in window.__SE_BOOTSTRAP, then "en:prod".
|
|
155
|
+
*/
|
|
156
|
+
i18nProfile?: string;
|
|
146
157
|
/**
|
|
147
158
|
* Skip the lazy auto-identify({}) at boot. Defaults to true (auto-identify on).
|
|
148
159
|
* Turn off when the host has its own identify orchestration and wants to
|
|
@@ -158,9 +169,9 @@ interface ShipeasyClientConfig {
|
|
|
158
169
|
* Pass `false` to disable everything, or a per-group object to narrow:
|
|
159
170
|
*
|
|
160
171
|
* ```ts
|
|
161
|
-
* shipeasy({
|
|
162
|
-
* shipeasy({
|
|
163
|
-
* shipeasy({
|
|
172
|
+
* shipeasy({ clientKey, autoCollect: false }); // off
|
|
173
|
+
* shipeasy({ clientKey, autoCollect: { errors: false } }); // vitals + engagement only
|
|
174
|
+
* shipeasy({ clientKey }); // all groups on
|
|
164
175
|
* ```
|
|
165
176
|
*/
|
|
166
177
|
autoCollect?: boolean | Partial<AutoCollectGroups>;
|
|
@@ -198,8 +209,8 @@ interface BootstrapPayload {
|
|
|
198
209
|
* the killswitch is not whole-killed and the map carries per-switch state.
|
|
199
210
|
*/
|
|
200
211
|
killswitches?: Record<string, boolean | Record<string, boolean>>;
|
|
201
|
-
/**
|
|
202
|
-
|
|
212
|
+
/** i18n profile the server rendered with, so the client loader matches. No key is embedded. */
|
|
213
|
+
i18nProfile?: string;
|
|
203
214
|
apiUrl?: string;
|
|
204
215
|
/** When true, tEl() returns marker-wrapped strings for devtools label editing. */
|
|
205
216
|
editLabels?: boolean;
|
package/dist/client/index.js
CHANGED
|
@@ -711,12 +711,14 @@ function shipeasy(opts) {
|
|
|
711
711
|
const ac = opts.autoCollect;
|
|
712
712
|
const blanket = ac === false ? false : true;
|
|
713
713
|
const groups = ac && typeof ac === "object" ? ac : void 0;
|
|
714
|
+
const baseUrl = opts.baseUrl ?? "https://cdn.shipeasy.ai";
|
|
714
715
|
const client = configureShipeasy({
|
|
715
|
-
sdkKey: opts.
|
|
716
|
-
baseUrl
|
|
716
|
+
sdkKey: opts.clientKey,
|
|
717
|
+
baseUrl,
|
|
717
718
|
autoGuardrails: blanket,
|
|
718
719
|
autoGuardrailGroups: groups
|
|
719
720
|
});
|
|
721
|
+
injectI18nLoader(opts.clientKey, baseUrl, opts.i18nProfile);
|
|
720
722
|
flags.notifyMounted();
|
|
721
723
|
if (opts.autoIdentify !== false) {
|
|
722
724
|
void client.identify({}).catch((err) => {
|
|
@@ -736,6 +738,23 @@ function getShipeasyClient() {
|
|
|
736
738
|
function _resetShipeasyForTests() {
|
|
737
739
|
_client?.destroy();
|
|
738
740
|
_client = null;
|
|
741
|
+
_i18nLoaderInjected = false;
|
|
742
|
+
}
|
|
743
|
+
var _i18nLoaderInjected = false;
|
|
744
|
+
function injectI18nLoader(clientKey, baseUrl, profileOpt) {
|
|
745
|
+
if (_i18nLoaderInjected || typeof document === "undefined") return;
|
|
746
|
+
if (!clientKey || typeof document.createElement !== "function" || !document.head) return;
|
|
747
|
+
_i18nLoaderInjected = true;
|
|
748
|
+
try {
|
|
749
|
+
const bs = getBootstrap();
|
|
750
|
+
const profile = profileOpt ?? bs?.i18nProfile ?? "en:prod";
|
|
751
|
+
const s = document.createElement("script");
|
|
752
|
+
s.src = `${baseUrl}/sdk/i18n/loader.js`;
|
|
753
|
+
s.setAttribute("data-key", clientKey);
|
|
754
|
+
s.setAttribute("data-profile", profile);
|
|
755
|
+
document.head.appendChild(s);
|
|
756
|
+
} catch {
|
|
757
|
+
}
|
|
739
758
|
}
|
|
740
759
|
function getBootstrap() {
|
|
741
760
|
if (typeof window === "undefined") return null;
|
|
@@ -1090,12 +1109,6 @@ var i18n = {
|
|
|
1090
1109
|
};
|
|
1091
1110
|
}
|
|
1092
1111
|
};
|
|
1093
|
-
if (typeof window !== "undefined") {
|
|
1094
|
-
const _initBs = window.__SE_BOOTSTRAP;
|
|
1095
|
-
if (_initBs?.apiKey && !_client) {
|
|
1096
|
-
shipeasy({ apiKey: _initBs.apiKey, baseUrl: _initBs.apiUrl });
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
1112
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1100
1113
|
0 && (module.exports = {
|
|
1101
1114
|
FlagsClientBrowser,
|
package/dist/client/index.mjs
CHANGED
|
@@ -668,12 +668,14 @@ function shipeasy(opts) {
|
|
|
668
668
|
const ac = opts.autoCollect;
|
|
669
669
|
const blanket = ac === false ? false : true;
|
|
670
670
|
const groups = ac && typeof ac === "object" ? ac : void 0;
|
|
671
|
+
const baseUrl = opts.baseUrl ?? "https://cdn.shipeasy.ai";
|
|
671
672
|
const client = configureShipeasy({
|
|
672
|
-
sdkKey: opts.
|
|
673
|
-
baseUrl
|
|
673
|
+
sdkKey: opts.clientKey,
|
|
674
|
+
baseUrl,
|
|
674
675
|
autoGuardrails: blanket,
|
|
675
676
|
autoGuardrailGroups: groups
|
|
676
677
|
});
|
|
678
|
+
injectI18nLoader(opts.clientKey, baseUrl, opts.i18nProfile);
|
|
677
679
|
flags.notifyMounted();
|
|
678
680
|
if (opts.autoIdentify !== false) {
|
|
679
681
|
void client.identify({}).catch((err) => {
|
|
@@ -693,6 +695,23 @@ function getShipeasyClient() {
|
|
|
693
695
|
function _resetShipeasyForTests() {
|
|
694
696
|
_client?.destroy();
|
|
695
697
|
_client = null;
|
|
698
|
+
_i18nLoaderInjected = false;
|
|
699
|
+
}
|
|
700
|
+
var _i18nLoaderInjected = false;
|
|
701
|
+
function injectI18nLoader(clientKey, baseUrl, profileOpt) {
|
|
702
|
+
if (_i18nLoaderInjected || typeof document === "undefined") return;
|
|
703
|
+
if (!clientKey || typeof document.createElement !== "function" || !document.head) return;
|
|
704
|
+
_i18nLoaderInjected = true;
|
|
705
|
+
try {
|
|
706
|
+
const bs = getBootstrap();
|
|
707
|
+
const profile = profileOpt ?? bs?.i18nProfile ?? "en:prod";
|
|
708
|
+
const s = document.createElement("script");
|
|
709
|
+
s.src = `${baseUrl}/sdk/i18n/loader.js`;
|
|
710
|
+
s.setAttribute("data-key", clientKey);
|
|
711
|
+
s.setAttribute("data-profile", profile);
|
|
712
|
+
document.head.appendChild(s);
|
|
713
|
+
} catch {
|
|
714
|
+
}
|
|
696
715
|
}
|
|
697
716
|
function getBootstrap() {
|
|
698
717
|
if (typeof window === "undefined") return null;
|
|
@@ -1047,12 +1066,6 @@ var i18n = {
|
|
|
1047
1066
|
};
|
|
1048
1067
|
}
|
|
1049
1068
|
};
|
|
1050
|
-
if (typeof window !== "undefined") {
|
|
1051
|
-
const _initBs = window.__SE_BOOTSTRAP;
|
|
1052
|
-
if (_initBs?.apiKey && !_client) {
|
|
1053
|
-
shipeasy({ apiKey: _initBs.apiKey, baseUrl: _initBs.apiUrl });
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
1069
|
export {
|
|
1057
1070
|
FlagsClientBrowser,
|
|
1058
1071
|
LABEL_MARKER_END,
|
package/dist/server/index.d.mts
CHANGED
|
@@ -132,20 +132,15 @@ declare function getShipeasyServerClient(): FlagsClient | null;
|
|
|
132
132
|
declare function _resetShipeasyServerForTests(): void;
|
|
133
133
|
interface ShipeasyServerConfig {
|
|
134
134
|
/**
|
|
135
|
-
* Server
|
|
136
|
-
* (requireKey("server"))
|
|
137
|
-
*
|
|
138
|
-
*
|
|
135
|
+
* Server key — the ONLY key the server entrypoint accepts. Authenticates
|
|
136
|
+
* flag/experiment fetches (requireKey("server")) AND SSR i18n string fetches
|
|
137
|
+
* (the /sdk/i18n/strings route accepts the server key for server-side use).
|
|
138
|
+
* Never embedded in browser output. The browser uses its own client key via
|
|
139
|
+
* `shipeasy({ clientKey })` from `@shipeasy/sdk/client` — the server never
|
|
140
|
+
* sees or forwards the client key. If omitted, flag/experiment/i18n loading
|
|
141
|
+
* is skipped and an error is logged.
|
|
139
142
|
*/
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Public client key — embedded in window.__SE_BOOTSTRAP and used by the
|
|
143
|
-
* browser SDK, and authenticates i18n string fetches (requireKey("client")).
|
|
144
|
-
* Safe to expose (e.g. NEXT_PUBLIC_ env vars). If omitted, i18n loading is
|
|
145
|
-
* skipped and an error is logged — it is NOT substituted with apiKey (a
|
|
146
|
-
* server key 401s against /sdk/i18n/strings).
|
|
147
|
-
*/
|
|
148
|
-
clientKey?: string;
|
|
143
|
+
serverKey?: string;
|
|
149
144
|
/** Raw URL or query string for applying ?se_ks_* / ?se_cf_* / ?se_exp_* overrides. */
|
|
150
145
|
urlOverrides?: string;
|
|
151
146
|
/** User attributes for flag and experiment evaluation. */
|
|
@@ -168,23 +163,24 @@ interface ShipeasyServerHandle {
|
|
|
168
163
|
*/
|
|
169
164
|
declare function shipeasy(opts: ShipeasyServerConfig): Promise<ShipeasyServerHandle>;
|
|
170
165
|
interface BootstrapHtmlOptions {
|
|
171
|
-
/**
|
|
172
|
-
apiKey: string;
|
|
173
|
-
/** i18n profile fed to the loader script. Defaults to "en:prod". */
|
|
166
|
+
/** i18n profile recorded in the bootstrap so the client loader matches SSR. Defaults to "en:prod". */
|
|
174
167
|
i18nProfile?: string;
|
|
175
168
|
/** When true, tEl() embeds label markers so the devtools can highlight them. */
|
|
176
169
|
editLabels?: boolean;
|
|
177
170
|
}
|
|
178
171
|
/**
|
|
179
|
-
* Returns a vanilla-JS
|
|
180
|
-
*
|
|
172
|
+
* Returns a vanilla-JS string for a single inline <script> tag. Handles
|
|
173
|
+
* everything the client needs at startup EXCEPT the key — no SDK key is ever
|
|
174
|
+
* embedded here (the server only knows the server key, which must stay
|
|
175
|
+
* server-side). The browser supplies its own client key via
|
|
176
|
+
* `shipeasy({ clientKey })` from @shipeasy/sdk/client, which also injects the
|
|
177
|
+
* runtime i18n loader. This script emits:
|
|
181
178
|
* - window.__se_devtools_config (when devtoolsAdminUrl is set)
|
|
182
|
-
* - window.__SE_BOOTSTRAP (flags + configs + experiments + i18n +
|
|
183
|
-
* - window.i18n shim from SSR strings (prevents hydration mismatches)
|
|
184
|
-
* -
|
|
179
|
+
* - window.__SE_BOOTSTRAP (flags + configs + experiments + i18n DATA + i18nProfile, NO key)
|
|
180
|
+
* - window.i18n shim from SSR strings (prevents hydration mismatches / FOUC)
|
|
181
|
+
* - devtools overlay loader when ?se / ?se_devtools is present
|
|
185
182
|
*
|
|
186
183
|
* Framework-agnostic: set innerHTML on a <script> element, nothing else required.
|
|
187
|
-
* Pass null for bootstrap on pages without flag evaluation — client still auto-inits.
|
|
188
184
|
*/
|
|
189
185
|
declare function getBootstrapHtml(bootstrap: BootstrapPayload | null, i18nData: I18nForRequest | null, opts: BootstrapHtmlOptions): string;
|
|
190
186
|
declare const flags: {
|
package/dist/server/index.d.ts
CHANGED
|
@@ -132,20 +132,15 @@ declare function getShipeasyServerClient(): FlagsClient | null;
|
|
|
132
132
|
declare function _resetShipeasyServerForTests(): void;
|
|
133
133
|
interface ShipeasyServerConfig {
|
|
134
134
|
/**
|
|
135
|
-
* Server
|
|
136
|
-
* (requireKey("server"))
|
|
137
|
-
*
|
|
138
|
-
*
|
|
135
|
+
* Server key — the ONLY key the server entrypoint accepts. Authenticates
|
|
136
|
+
* flag/experiment fetches (requireKey("server")) AND SSR i18n string fetches
|
|
137
|
+
* (the /sdk/i18n/strings route accepts the server key for server-side use).
|
|
138
|
+
* Never embedded in browser output. The browser uses its own client key via
|
|
139
|
+
* `shipeasy({ clientKey })` from `@shipeasy/sdk/client` — the server never
|
|
140
|
+
* sees or forwards the client key. If omitted, flag/experiment/i18n loading
|
|
141
|
+
* is skipped and an error is logged.
|
|
139
142
|
*/
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Public client key — embedded in window.__SE_BOOTSTRAP and used by the
|
|
143
|
-
* browser SDK, and authenticates i18n string fetches (requireKey("client")).
|
|
144
|
-
* Safe to expose (e.g. NEXT_PUBLIC_ env vars). If omitted, i18n loading is
|
|
145
|
-
* skipped and an error is logged — it is NOT substituted with apiKey (a
|
|
146
|
-
* server key 401s against /sdk/i18n/strings).
|
|
147
|
-
*/
|
|
148
|
-
clientKey?: string;
|
|
143
|
+
serverKey?: string;
|
|
149
144
|
/** Raw URL or query string for applying ?se_ks_* / ?se_cf_* / ?se_exp_* overrides. */
|
|
150
145
|
urlOverrides?: string;
|
|
151
146
|
/** User attributes for flag and experiment evaluation. */
|
|
@@ -168,23 +163,24 @@ interface ShipeasyServerHandle {
|
|
|
168
163
|
*/
|
|
169
164
|
declare function shipeasy(opts: ShipeasyServerConfig): Promise<ShipeasyServerHandle>;
|
|
170
165
|
interface BootstrapHtmlOptions {
|
|
171
|
-
/**
|
|
172
|
-
apiKey: string;
|
|
173
|
-
/** i18n profile fed to the loader script. Defaults to "en:prod". */
|
|
166
|
+
/** i18n profile recorded in the bootstrap so the client loader matches SSR. Defaults to "en:prod". */
|
|
174
167
|
i18nProfile?: string;
|
|
175
168
|
/** When true, tEl() embeds label markers so the devtools can highlight them. */
|
|
176
169
|
editLabels?: boolean;
|
|
177
170
|
}
|
|
178
171
|
/**
|
|
179
|
-
* Returns a vanilla-JS
|
|
180
|
-
*
|
|
172
|
+
* Returns a vanilla-JS string for a single inline <script> tag. Handles
|
|
173
|
+
* everything the client needs at startup EXCEPT the key — no SDK key is ever
|
|
174
|
+
* embedded here (the server only knows the server key, which must stay
|
|
175
|
+
* server-side). The browser supplies its own client key via
|
|
176
|
+
* `shipeasy({ clientKey })` from @shipeasy/sdk/client, which also injects the
|
|
177
|
+
* runtime i18n loader. This script emits:
|
|
181
178
|
* - window.__se_devtools_config (when devtoolsAdminUrl is set)
|
|
182
|
-
* - window.__SE_BOOTSTRAP (flags + configs + experiments + i18n +
|
|
183
|
-
* - window.i18n shim from SSR strings (prevents hydration mismatches)
|
|
184
|
-
* -
|
|
179
|
+
* - window.__SE_BOOTSTRAP (flags + configs + experiments + i18n DATA + i18nProfile, NO key)
|
|
180
|
+
* - window.i18n shim from SSR strings (prevents hydration mismatches / FOUC)
|
|
181
|
+
* - devtools overlay loader when ?se / ?se_devtools is present
|
|
185
182
|
*
|
|
186
183
|
* Framework-agnostic: set innerHTML on a <script> element, nothing else required.
|
|
187
|
-
* Pass null for bootstrap on pages without flag evaluation — client still auto-inits.
|
|
188
184
|
*/
|
|
189
185
|
declare function getBootstrapHtml(bootstrap: BootstrapPayload | null, i18nData: I18nForRequest | null, opts: BootstrapHtmlOptions): string;
|
|
190
186
|
declare const flags: {
|
package/dist/server/index.js
CHANGED
|
@@ -486,7 +486,6 @@ async function fetchLabelsForSSR(opts) {
|
|
|
486
486
|
}
|
|
487
487
|
}
|
|
488
488
|
var _server = null;
|
|
489
|
-
var _rememberedClientKey = null;
|
|
490
489
|
function configureShipeasyServer(opts) {
|
|
491
490
|
if (_server) return _server;
|
|
492
491
|
_server = new FlagsClient(opts);
|
|
@@ -500,21 +499,14 @@ function _resetShipeasyServerForTests() {
|
|
|
500
499
|
_server = null;
|
|
501
500
|
}
|
|
502
501
|
async function shipeasy(opts) {
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
if (opts.clientKey && !_rememberedClientKey) _rememberedClientKey = opts.clientKey;
|
|
506
|
-
if (!apiKey) {
|
|
502
|
+
const serverKey = opts.serverKey ?? "";
|
|
503
|
+
if (!serverKey) {
|
|
507
504
|
console.error(
|
|
508
|
-
"[shipeasy] No server key \u2014 flags
|
|
509
|
-
);
|
|
510
|
-
}
|
|
511
|
-
if (!clientKey) {
|
|
512
|
-
console.error(
|
|
513
|
-
"[shipeasy] No client key \u2014 i18n strings skipped, falling back to hardcoded text. Pass `clientKey` to shipeasy() with your public client key (NEXT_PUBLIC_SHIPEASY_CLIENT_KEY). Do not pass a server key here \u2014 /sdk/i18n/strings requires a client key and will 401."
|
|
505
|
+
"[shipeasy] No server key \u2014 flags, experiments and SSR i18n skipped. Pass `serverKey` to shipeasy() from @shipeasy/sdk/server with your server key (SHIPEASY_SERVER_KEY). Set it as a Worker secret with `wrangler secret put SHIPEASY_SERVER_KEY` (or add it to .env for local dev). Do not pass a client key here \u2014 the server entrypoint only accepts the server key."
|
|
514
506
|
);
|
|
515
507
|
}
|
|
516
508
|
const profile = opts.i18nDefaultProfile ?? "en:prod";
|
|
517
|
-
flags.configure({ apiKey });
|
|
509
|
+
flags.configure({ apiKey: serverKey });
|
|
518
510
|
let resolvedUrlOverrides = opts.urlOverrides;
|
|
519
511
|
if (!resolvedUrlOverrides) {
|
|
520
512
|
try {
|
|
@@ -535,8 +527,8 @@ async function shipeasy(opts) {
|
|
|
535
527
|
const editLabels = resolvedUrlOverrides ? new URLSearchParams(resolvedUrlOverrides).has("se_edit_labels") : false;
|
|
536
528
|
globalThis[_EDIT_MODE_SSR_SYM] = editLabels;
|
|
537
529
|
await Promise.allSettled([
|
|
538
|
-
|
|
539
|
-
|
|
530
|
+
serverKey ? flags.initOnce() : Promise.resolve(),
|
|
531
|
+
serverKey ? i18n.init(serverKey, profile) : Promise.resolve()
|
|
540
532
|
]);
|
|
541
533
|
const bootstrap = flags.evaluate(opts.user ?? {}, resolvedUrlOverrides);
|
|
542
534
|
const i18nData = i18n.getForRequest();
|
|
@@ -546,7 +538,6 @@ async function shipeasy(opts) {
|
|
|
546
538
|
experiments: bootstrap.experiments,
|
|
547
539
|
getBootstrapHtml() {
|
|
548
540
|
return getBootstrapHtml(bootstrap, i18nData, {
|
|
549
|
-
apiKey: clientKey,
|
|
550
541
|
editLabels,
|
|
551
542
|
i18nProfile: profile
|
|
552
543
|
});
|
|
@@ -561,7 +552,9 @@ function getBootstrapHtml(bootstrap, i18nData, opts) {
|
|
|
561
552
|
flags: bootstrap?.flags ?? {},
|
|
562
553
|
configs: bootstrap?.configs ?? {},
|
|
563
554
|
experiments: bootstrap?.experiments ?? {},
|
|
564
|
-
|
|
555
|
+
// No key here — the server only knows the server key, which must never reach
|
|
556
|
+
// the browser. The client supplies its own client key via shipeasy({ clientKey }).
|
|
557
|
+
i18nProfile: profile,
|
|
565
558
|
apiUrl
|
|
566
559
|
};
|
|
567
560
|
if (i18nData) payload.i18n = i18nData;
|
|
@@ -575,9 +568,6 @@ function getBootstrapHtml(bootstrap, i18nData, opts) {
|
|
|
575
568
|
`(function(){var d=window.__SE_BOOTSTRAP.i18n;if(!d)return;window.i18n={locale:d.locale,t:function(k,v){var r=d.strings[k];if(!r)return k;return v?r.replace(/\\{\\{(\\w+)\\}\\}/g,function(_,p){return v[p]!==undefined?String(v[p]):'{{'+p+'}}'}):r;},on:function(){return function(){};}};})();`
|
|
576
569
|
);
|
|
577
570
|
}
|
|
578
|
-
parts.push(
|
|
579
|
-
`(function(){var s=document.createElement('script');s.src=${JSON.stringify(`${apiUrl}/sdk/i18n/loader.js`)};s.setAttribute('data-key',${JSON.stringify(opts.apiKey)});s.setAttribute('data-profile',${JSON.stringify(profile)});document.head.appendChild(s);})();`
|
|
580
|
-
);
|
|
581
571
|
parts.push(
|
|
582
572
|
`(function(){var p=new URLSearchParams(location.search);if(p.has('se')||p.has('se_devtools')){var d=document.createElement('script');d.src='https://shipeasy.ai/se-devtools.js';document.head.appendChild(d);}})();`
|
|
583
573
|
);
|
package/dist/server/index.mjs
CHANGED
|
@@ -443,7 +443,6 @@ async function fetchLabelsForSSR(opts) {
|
|
|
443
443
|
}
|
|
444
444
|
}
|
|
445
445
|
var _server = null;
|
|
446
|
-
var _rememberedClientKey = null;
|
|
447
446
|
function configureShipeasyServer(opts) {
|
|
448
447
|
if (_server) return _server;
|
|
449
448
|
_server = new FlagsClient(opts);
|
|
@@ -457,21 +456,14 @@ function _resetShipeasyServerForTests() {
|
|
|
457
456
|
_server = null;
|
|
458
457
|
}
|
|
459
458
|
async function shipeasy(opts) {
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
if (opts.clientKey && !_rememberedClientKey) _rememberedClientKey = opts.clientKey;
|
|
463
|
-
if (!apiKey) {
|
|
459
|
+
const serverKey = opts.serverKey ?? "";
|
|
460
|
+
if (!serverKey) {
|
|
464
461
|
console.error(
|
|
465
|
-
"[shipeasy] No server key \u2014 flags
|
|
466
|
-
);
|
|
467
|
-
}
|
|
468
|
-
if (!clientKey) {
|
|
469
|
-
console.error(
|
|
470
|
-
"[shipeasy] No client key \u2014 i18n strings skipped, falling back to hardcoded text. Pass `clientKey` to shipeasy() with your public client key (NEXT_PUBLIC_SHIPEASY_CLIENT_KEY). Do not pass a server key here \u2014 /sdk/i18n/strings requires a client key and will 401."
|
|
462
|
+
"[shipeasy] No server key \u2014 flags, experiments and SSR i18n skipped. Pass `serverKey` to shipeasy() from @shipeasy/sdk/server with your server key (SHIPEASY_SERVER_KEY). Set it as a Worker secret with `wrangler secret put SHIPEASY_SERVER_KEY` (or add it to .env for local dev). Do not pass a client key here \u2014 the server entrypoint only accepts the server key."
|
|
471
463
|
);
|
|
472
464
|
}
|
|
473
465
|
const profile = opts.i18nDefaultProfile ?? "en:prod";
|
|
474
|
-
flags.configure({ apiKey });
|
|
466
|
+
flags.configure({ apiKey: serverKey });
|
|
475
467
|
let resolvedUrlOverrides = opts.urlOverrides;
|
|
476
468
|
if (!resolvedUrlOverrides) {
|
|
477
469
|
try {
|
|
@@ -492,8 +484,8 @@ async function shipeasy(opts) {
|
|
|
492
484
|
const editLabels = resolvedUrlOverrides ? new URLSearchParams(resolvedUrlOverrides).has("se_edit_labels") : false;
|
|
493
485
|
globalThis[_EDIT_MODE_SSR_SYM] = editLabels;
|
|
494
486
|
await Promise.allSettled([
|
|
495
|
-
|
|
496
|
-
|
|
487
|
+
serverKey ? flags.initOnce() : Promise.resolve(),
|
|
488
|
+
serverKey ? i18n.init(serverKey, profile) : Promise.resolve()
|
|
497
489
|
]);
|
|
498
490
|
const bootstrap = flags.evaluate(opts.user ?? {}, resolvedUrlOverrides);
|
|
499
491
|
const i18nData = i18n.getForRequest();
|
|
@@ -503,7 +495,6 @@ async function shipeasy(opts) {
|
|
|
503
495
|
experiments: bootstrap.experiments,
|
|
504
496
|
getBootstrapHtml() {
|
|
505
497
|
return getBootstrapHtml(bootstrap, i18nData, {
|
|
506
|
-
apiKey: clientKey,
|
|
507
498
|
editLabels,
|
|
508
499
|
i18nProfile: profile
|
|
509
500
|
});
|
|
@@ -518,7 +509,9 @@ function getBootstrapHtml(bootstrap, i18nData, opts) {
|
|
|
518
509
|
flags: bootstrap?.flags ?? {},
|
|
519
510
|
configs: bootstrap?.configs ?? {},
|
|
520
511
|
experiments: bootstrap?.experiments ?? {},
|
|
521
|
-
|
|
512
|
+
// No key here — the server only knows the server key, which must never reach
|
|
513
|
+
// the browser. The client supplies its own client key via shipeasy({ clientKey }).
|
|
514
|
+
i18nProfile: profile,
|
|
522
515
|
apiUrl
|
|
523
516
|
};
|
|
524
517
|
if (i18nData) payload.i18n = i18nData;
|
|
@@ -532,9 +525,6 @@ function getBootstrapHtml(bootstrap, i18nData, opts) {
|
|
|
532
525
|
`(function(){var d=window.__SE_BOOTSTRAP.i18n;if(!d)return;window.i18n={locale:d.locale,t:function(k,v){var r=d.strings[k];if(!r)return k;return v?r.replace(/\\{\\{(\\w+)\\}\\}/g,function(_,p){return v[p]!==undefined?String(v[p]):'{{'+p+'}}'}):r;},on:function(){return function(){};}};})();`
|
|
533
526
|
);
|
|
534
527
|
}
|
|
535
|
-
parts.push(
|
|
536
|
-
`(function(){var s=document.createElement('script');s.src=${JSON.stringify(`${apiUrl}/sdk/i18n/loader.js`)};s.setAttribute('data-key',${JSON.stringify(opts.apiKey)});s.setAttribute('data-profile',${JSON.stringify(profile)});document.head.appendChild(s);})();`
|
|
537
|
-
);
|
|
538
528
|
parts.push(
|
|
539
529
|
`(function(){var p=new URLSearchParams(location.search);if(p.has('se')||p.has('se_devtools')){var d=document.createElement('script');d.src='https://shipeasy.ai/se-devtools.js';document.head.appendChild(d);}})();`
|
|
540
530
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipeasy/sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Shipeasy SDK — feature gates, runtime configs, experiments, and metrics for the Shipeasy hosted service.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://shipeasy.ai",
|