@shipeasy/sdk 2.5.1 → 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 -18
- package/dist/server/index.d.ts +18 -18
- package/dist/server/index.js +13 -15
- package/dist/server/index.mjs +13 -15
- 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,16 +132,15 @@ declare function getShipeasyServerClient(): FlagsClient | null;
|
|
|
132
132
|
declare function _resetShipeasyServerForTests(): void;
|
|
133
133
|
interface ShipeasyServerConfig {
|
|
134
134
|
/**
|
|
135
|
-
* Server
|
|
136
|
-
*
|
|
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.
|
|
137
142
|
*/
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Public client key — embedded in window.__SE_BOOTSTRAP and used by the
|
|
141
|
-
* browser SDK. Safe to expose (e.g. NEXT_PUBLIC_ env vars).
|
|
142
|
-
* Defaults to apiKey for single-key setups.
|
|
143
|
-
*/
|
|
144
|
-
clientKey?: string;
|
|
143
|
+
serverKey?: string;
|
|
145
144
|
/** Raw URL or query string for applying ?se_ks_* / ?se_cf_* / ?se_exp_* overrides. */
|
|
146
145
|
urlOverrides?: string;
|
|
147
146
|
/** User attributes for flag and experiment evaluation. */
|
|
@@ -164,23 +163,24 @@ interface ShipeasyServerHandle {
|
|
|
164
163
|
*/
|
|
165
164
|
declare function shipeasy(opts: ShipeasyServerConfig): Promise<ShipeasyServerHandle>;
|
|
166
165
|
interface BootstrapHtmlOptions {
|
|
167
|
-
/**
|
|
168
|
-
apiKey: string;
|
|
169
|
-
/** 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". */
|
|
170
167
|
i18nProfile?: string;
|
|
171
168
|
/** When true, tEl() embeds label markers so the devtools can highlight them. */
|
|
172
169
|
editLabels?: boolean;
|
|
173
170
|
}
|
|
174
171
|
/**
|
|
175
|
-
* Returns a vanilla-JS
|
|
176
|
-
*
|
|
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:
|
|
177
178
|
* - window.__se_devtools_config (when devtoolsAdminUrl is set)
|
|
178
|
-
* - window.__SE_BOOTSTRAP (flags + configs + experiments + i18n +
|
|
179
|
-
* - window.i18n shim from SSR strings (prevents hydration mismatches)
|
|
180
|
-
* -
|
|
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
|
|
181
182
|
*
|
|
182
183
|
* Framework-agnostic: set innerHTML on a <script> element, nothing else required.
|
|
183
|
-
* Pass null for bootstrap on pages without flag evaluation — client still auto-inits.
|
|
184
184
|
*/
|
|
185
185
|
declare function getBootstrapHtml(bootstrap: BootstrapPayload | null, i18nData: I18nForRequest | null, opts: BootstrapHtmlOptions): string;
|
|
186
186
|
declare const flags: {
|
package/dist/server/index.d.ts
CHANGED
|
@@ -132,16 +132,15 @@ declare function getShipeasyServerClient(): FlagsClient | null;
|
|
|
132
132
|
declare function _resetShipeasyServerForTests(): void;
|
|
133
133
|
interface ShipeasyServerConfig {
|
|
134
134
|
/**
|
|
135
|
-
* Server
|
|
136
|
-
*
|
|
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.
|
|
137
142
|
*/
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Public client key — embedded in window.__SE_BOOTSTRAP and used by the
|
|
141
|
-
* browser SDK. Safe to expose (e.g. NEXT_PUBLIC_ env vars).
|
|
142
|
-
* Defaults to apiKey for single-key setups.
|
|
143
|
-
*/
|
|
144
|
-
clientKey?: string;
|
|
143
|
+
serverKey?: string;
|
|
145
144
|
/** Raw URL or query string for applying ?se_ks_* / ?se_cf_* / ?se_exp_* overrides. */
|
|
146
145
|
urlOverrides?: string;
|
|
147
146
|
/** User attributes for flag and experiment evaluation. */
|
|
@@ -164,23 +163,24 @@ interface ShipeasyServerHandle {
|
|
|
164
163
|
*/
|
|
165
164
|
declare function shipeasy(opts: ShipeasyServerConfig): Promise<ShipeasyServerHandle>;
|
|
166
165
|
interface BootstrapHtmlOptions {
|
|
167
|
-
/**
|
|
168
|
-
apiKey: string;
|
|
169
|
-
/** 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". */
|
|
170
167
|
i18nProfile?: string;
|
|
171
168
|
/** When true, tEl() embeds label markers so the devtools can highlight them. */
|
|
172
169
|
editLabels?: boolean;
|
|
173
170
|
}
|
|
174
171
|
/**
|
|
175
|
-
* Returns a vanilla-JS
|
|
176
|
-
*
|
|
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:
|
|
177
178
|
* - window.__se_devtools_config (when devtoolsAdminUrl is set)
|
|
178
|
-
* - window.__SE_BOOTSTRAP (flags + configs + experiments + i18n +
|
|
179
|
-
* - window.i18n shim from SSR strings (prevents hydration mismatches)
|
|
180
|
-
* -
|
|
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
|
|
181
182
|
*
|
|
182
183
|
* Framework-agnostic: set innerHTML on a <script> element, nothing else required.
|
|
183
|
-
* Pass null for bootstrap on pages without flag evaluation — client still auto-inits.
|
|
184
184
|
*/
|
|
185
185
|
declare function getBootstrapHtml(bootstrap: BootstrapPayload | null, i18nData: I18nForRequest | null, opts: BootstrapHtmlOptions): string;
|
|
186
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,16 +499,14 @@ function _resetShipeasyServerForTests() {
|
|
|
500
499
|
_server = null;
|
|
501
500
|
}
|
|
502
501
|
async function shipeasy(opts) {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
502
|
+
const serverKey = opts.serverKey ?? "";
|
|
503
|
+
if (!serverKey) {
|
|
504
|
+
console.error(
|
|
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."
|
|
506
|
+
);
|
|
507
507
|
}
|
|
508
|
-
const apiKey = opts.apiKey ?? opts.clientKey ?? "";
|
|
509
|
-
const clientKey = opts.clientKey ?? _rememberedClientKey ?? opts.apiKey ?? "";
|
|
510
|
-
if (opts.clientKey && !_rememberedClientKey) _rememberedClientKey = opts.clientKey;
|
|
511
508
|
const profile = opts.i18nDefaultProfile ?? "en:prod";
|
|
512
|
-
flags.configure({ apiKey });
|
|
509
|
+
flags.configure({ apiKey: serverKey });
|
|
513
510
|
let resolvedUrlOverrides = opts.urlOverrides;
|
|
514
511
|
if (!resolvedUrlOverrides) {
|
|
515
512
|
try {
|
|
@@ -529,7 +526,10 @@ async function shipeasy(opts) {
|
|
|
529
526
|
}
|
|
530
527
|
const editLabels = resolvedUrlOverrides ? new URLSearchParams(resolvedUrlOverrides).has("se_edit_labels") : false;
|
|
531
528
|
globalThis[_EDIT_MODE_SSR_SYM] = editLabels;
|
|
532
|
-
await Promise.allSettled([
|
|
529
|
+
await Promise.allSettled([
|
|
530
|
+
serverKey ? flags.initOnce() : Promise.resolve(),
|
|
531
|
+
serverKey ? i18n.init(serverKey, profile) : Promise.resolve()
|
|
532
|
+
]);
|
|
533
533
|
const bootstrap = flags.evaluate(opts.user ?? {}, resolvedUrlOverrides);
|
|
534
534
|
const i18nData = i18n.getForRequest();
|
|
535
535
|
return {
|
|
@@ -538,7 +538,6 @@ async function shipeasy(opts) {
|
|
|
538
538
|
experiments: bootstrap.experiments,
|
|
539
539
|
getBootstrapHtml() {
|
|
540
540
|
return getBootstrapHtml(bootstrap, i18nData, {
|
|
541
|
-
apiKey: clientKey,
|
|
542
541
|
editLabels,
|
|
543
542
|
i18nProfile: profile
|
|
544
543
|
});
|
|
@@ -553,7 +552,9 @@ function getBootstrapHtml(bootstrap, i18nData, opts) {
|
|
|
553
552
|
flags: bootstrap?.flags ?? {},
|
|
554
553
|
configs: bootstrap?.configs ?? {},
|
|
555
554
|
experiments: bootstrap?.experiments ?? {},
|
|
556
|
-
|
|
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,
|
|
557
558
|
apiUrl
|
|
558
559
|
};
|
|
559
560
|
if (i18nData) payload.i18n = i18nData;
|
|
@@ -567,9 +568,6 @@ function getBootstrapHtml(bootstrap, i18nData, opts) {
|
|
|
567
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(){};}};})();`
|
|
568
569
|
);
|
|
569
570
|
}
|
|
570
|
-
parts.push(
|
|
571
|
-
`(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);})();`
|
|
572
|
-
);
|
|
573
571
|
parts.push(
|
|
574
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);}})();`
|
|
575
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,16 +456,14 @@ function _resetShipeasyServerForTests() {
|
|
|
457
456
|
_server = null;
|
|
458
457
|
}
|
|
459
458
|
async function shipeasy(opts) {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
459
|
+
const serverKey = opts.serverKey ?? "";
|
|
460
|
+
if (!serverKey) {
|
|
461
|
+
console.error(
|
|
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."
|
|
463
|
+
);
|
|
464
464
|
}
|
|
465
|
-
const apiKey = opts.apiKey ?? opts.clientKey ?? "";
|
|
466
|
-
const clientKey = opts.clientKey ?? _rememberedClientKey ?? opts.apiKey ?? "";
|
|
467
|
-
if (opts.clientKey && !_rememberedClientKey) _rememberedClientKey = opts.clientKey;
|
|
468
465
|
const profile = opts.i18nDefaultProfile ?? "en:prod";
|
|
469
|
-
flags.configure({ apiKey });
|
|
466
|
+
flags.configure({ apiKey: serverKey });
|
|
470
467
|
let resolvedUrlOverrides = opts.urlOverrides;
|
|
471
468
|
if (!resolvedUrlOverrides) {
|
|
472
469
|
try {
|
|
@@ -486,7 +483,10 @@ async function shipeasy(opts) {
|
|
|
486
483
|
}
|
|
487
484
|
const editLabels = resolvedUrlOverrides ? new URLSearchParams(resolvedUrlOverrides).has("se_edit_labels") : false;
|
|
488
485
|
globalThis[_EDIT_MODE_SSR_SYM] = editLabels;
|
|
489
|
-
await Promise.allSettled([
|
|
486
|
+
await Promise.allSettled([
|
|
487
|
+
serverKey ? flags.initOnce() : Promise.resolve(),
|
|
488
|
+
serverKey ? i18n.init(serverKey, profile) : Promise.resolve()
|
|
489
|
+
]);
|
|
490
490
|
const bootstrap = flags.evaluate(opts.user ?? {}, resolvedUrlOverrides);
|
|
491
491
|
const i18nData = i18n.getForRequest();
|
|
492
492
|
return {
|
|
@@ -495,7 +495,6 @@ async function shipeasy(opts) {
|
|
|
495
495
|
experiments: bootstrap.experiments,
|
|
496
496
|
getBootstrapHtml() {
|
|
497
497
|
return getBootstrapHtml(bootstrap, i18nData, {
|
|
498
|
-
apiKey: clientKey,
|
|
499
498
|
editLabels,
|
|
500
499
|
i18nProfile: profile
|
|
501
500
|
});
|
|
@@ -510,7 +509,9 @@ function getBootstrapHtml(bootstrap, i18nData, opts) {
|
|
|
510
509
|
flags: bootstrap?.flags ?? {},
|
|
511
510
|
configs: bootstrap?.configs ?? {},
|
|
512
511
|
experiments: bootstrap?.experiments ?? {},
|
|
513
|
-
|
|
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,
|
|
514
515
|
apiUrl
|
|
515
516
|
};
|
|
516
517
|
if (i18nData) payload.i18n = i18nData;
|
|
@@ -524,9 +525,6 @@ function getBootstrapHtml(bootstrap, i18nData, opts) {
|
|
|
524
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(){};}};})();`
|
|
525
526
|
);
|
|
526
527
|
}
|
|
527
|
-
parts.push(
|
|
528
|
-
`(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);})();`
|
|
529
|
-
);
|
|
530
528
|
parts.push(
|
|
531
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);}})();`
|
|
532
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",
|