langsys-js-typescript 0.2.0 → 0.2.2

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/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 0.2.1 - 2026-06-11
2
+
3
+ ### Changed
4
+
5
+ - **Migrated off the deprecated API routes onto the current endpoints.** No public API change — the same `t()`, `<Phrase>`, and `<Translate>` usage now talks to:
6
+ - Reads: `GET /translations?project_id=…&locale=…` (was the deprecated `GET /projects/{id}/translations`).
7
+ - Writes: `POST /translatable-items` with a unified `{ project_id, translatable_items: [{ type: 'phrase' | 'content_block', … }] }` body (was the deprecated `POST /projects/{id}/tokens` and `POST /projects/{id}/content-blocks`).
8
+ - Missing-phrase registration now chunks into batches of 200 to respect the `/translatable-items` per-request cap.
9
+ - Added `LangsysAppAPI.createTranslatableItems()` as the single write entry point for both phrases and content blocks.
10
+
1
11
  ## 0.1.0 - 2026-05-19
2
12
 
3
13
  Initial public release. Framework-agnostic TypeScript SDK for the Langsys Translation Manager — the foundation that `langsys-js-svelte` (and future framework-specific bindings) build on.
package/dist/index.d.mts CHANGED
@@ -239,6 +239,14 @@ declare class Translations {
239
239
  private missingToken;
240
240
  private scheduleTokenFlush;
241
241
  setup(config: iLangsysConfig): void;
242
+ /**
243
+ * Record that a locale's catalog is already present without fetching —
244
+ * e.g. after an SSR handoff seeds `sTranslations` + `currentlyLoadedLocale`.
245
+ * This primes the same `lastLoaded` cache `change()` consults, so the first
246
+ * settle for that locale is a cache hit (no redundant fetch) while every
247
+ * later switch *to* it still flows through `change()` normally.
248
+ */
249
+ markLoaded(locale: string): void;
242
250
  /**
243
251
  * React to a user-locale change. Fetches translations if we haven't
244
252
  * loaded this locale within the last 60s (or if forced).
@@ -511,6 +519,12 @@ declare class LangsysAppAPIClass {
511
519
  setBaseUrl(url: string): void;
512
520
  validate(config: iLangsysConfig): Promise<ResponseObject>;
513
521
  getTranslations(locale: string): Promise<ResponseObject>;
522
+ /**
523
+ * Register phrases and/or content blocks via the current unified endpoint.
524
+ * Each item carries `type: 'phrase' | 'content_block'`. Replaces the
525
+ * deprecated `projects/{id}/tokens` and `projects/{id}/content-blocks` routes.
526
+ */
527
+ createTranslatableItems(items: Array<Record<string, unknown>>): Promise<ResponseObject>;
514
528
  post(path: string, data?: Record<string, unknown>): Promise<ResponseObject>;
515
529
  get(path: string, data?: Record<string, unknown>): Promise<ResponseObject>;
516
530
  delete(path: string, data?: Record<string, unknown>): Promise<ResponseObject>;
package/dist/index.d.ts CHANGED
@@ -239,6 +239,14 @@ declare class Translations {
239
239
  private missingToken;
240
240
  private scheduleTokenFlush;
241
241
  setup(config: iLangsysConfig): void;
242
+ /**
243
+ * Record that a locale's catalog is already present without fetching —
244
+ * e.g. after an SSR handoff seeds `sTranslations` + `currentlyLoadedLocale`.
245
+ * This primes the same `lastLoaded` cache `change()` consults, so the first
246
+ * settle for that locale is a cache hit (no redundant fetch) while every
247
+ * later switch *to* it still flows through `change()` normally.
248
+ */
249
+ markLoaded(locale: string): void;
242
250
  /**
243
251
  * React to a user-locale change. Fetches translations if we haven't
244
252
  * loaded this locale within the last 60s (or if forced).
@@ -511,6 +519,12 @@ declare class LangsysAppAPIClass {
511
519
  setBaseUrl(url: string): void;
512
520
  validate(config: iLangsysConfig): Promise<ResponseObject>;
513
521
  getTranslations(locale: string): Promise<ResponseObject>;
522
+ /**
523
+ * Register phrases and/or content blocks via the current unified endpoint.
524
+ * Each item carries `type: 'phrase' | 'content_block'`. Replaces the
525
+ * deprecated `projects/{id}/tokens` and `projects/{id}/content-blocks` routes.
526
+ */
527
+ createTranslatableItems(items: Array<Record<string, unknown>>): Promise<ResponseObject>;
514
528
  post(path: string, data?: Record<string, unknown>): Promise<ResponseObject>;
515
529
  get(path: string, data?: Record<string, unknown>): Promise<ResponseObject>;
516
530
  delete(path: string, data?: Record<string, unknown>): Promise<ResponseObject>;
package/dist/index.js CHANGED
@@ -93,7 +93,18 @@ var LangsysAppAPIClass = class {
93
93
  return await this.get("authorize-project/[projectid]");
94
94
  }
95
95
  async getTranslations(locale) {
96
- return await this.get("projects/[projectid]/translations", { locale });
96
+ return await this.get("translations", { project_id: this.config.projectid, locale });
97
+ }
98
+ /**
99
+ * Register phrases and/or content blocks via the current unified endpoint.
100
+ * Each item carries `type: 'phrase' | 'content_block'`. Replaces the
101
+ * deprecated `projects/{id}/tokens` and `projects/{id}/content-blocks` routes.
102
+ */
103
+ async createTranslatableItems(items) {
104
+ return await this.post("translatable-items", {
105
+ project_id: this.config.projectid,
106
+ translatable_items: items
107
+ });
97
108
  }
98
109
  async post(path, data = {}) {
99
110
  return await this.send("POST", path, data);
@@ -431,6 +442,18 @@ var Translations = class {
431
442
  this.debug.log(`SSR environment detected - using '${strategy}' token strategy`);
432
443
  }
433
444
  }
445
+ /**
446
+ * Record that a locale's catalog is already present without fetching —
447
+ * e.g. after an SSR handoff seeds `sTranslations` + `currentlyLoadedLocale`.
448
+ * This primes the same `lastLoaded` cache `change()` consults, so the first
449
+ * settle for that locale is a cache hit (no redundant fetch) while every
450
+ * later switch *to* it still flows through `change()` normally.
451
+ */
452
+ markLoaded(locale) {
453
+ if (!locale) return;
454
+ this.locale = locale;
455
+ this.lastLoaded[locale] = (/* @__PURE__ */ new Date()).getTime() / 1e3;
456
+ }
434
457
  /**
435
458
  * React to a user-locale change. Fetches translations if we haven't
436
459
  * loaded this locale within the last 60s (or if forced).
@@ -480,20 +503,23 @@ var Translations = class {
480
503
  if (!this.missingTokens.length) return false;
481
504
  this.debug.log("CREATE MISSING TOKENS", this.missingTokens);
482
505
  try {
483
- const tokensForApi = this.missingTokens.map((tokenObj) => ({
484
- projectid: tokenObj.projectid,
485
- token: tokenObj.token,
506
+ const phraseItems = this.missingTokens.map((tokenObj) => ({
507
+ type: "phrase",
508
+ phrase: tokenObj.token,
486
509
  category: tokenObj.category || null
487
510
  }));
488
- const response = await LangsysAppAPI.post("projects/[projectid]/tokens", {
489
- tokens: tokensForApi
490
- });
491
- if (!response.status) {
492
- if (response.errors) {
493
- this.debug.log("TOKEN UPDATE FAIL", this.missingTokens);
494
- this.debug.error("Error updating project tokens", response.errors);
511
+ const BATCH_SIZE = 200;
512
+ for (let offset = 0; offset < phraseItems.length; offset += BATCH_SIZE) {
513
+ const response = await LangsysAppAPI.createTranslatableItems(
514
+ phraseItems.slice(offset, offset + BATCH_SIZE)
515
+ );
516
+ if (!response.status) {
517
+ if (response.errors) {
518
+ this.debug.log("TOKEN UPDATE FAIL", this.missingTokens);
519
+ this.debug.error("Error updating project tokens", response.errors);
520
+ }
521
+ return false;
495
522
  }
496
- return false;
497
523
  }
498
524
  this.missingTokens.forEach((tokenObj) => {
499
525
  const lookupCat = tokenObj.category || "__uncategorized__";
@@ -642,12 +668,14 @@ var LangsysAppClass = class {
642
668
  this.debug.log("Populated sTranslations with initial data for locale:", initialTranslationsLocale);
643
669
  }
644
670
  this.Translations.setup(this.config);
671
+ if (initialTranslations2 && initialTranslationsLocale) {
672
+ this.Translations.markLoaded(initialTranslationsLocale);
673
+ }
645
674
  this.config.sUserLocale.subscribe((locale) => {
646
675
  if (!validateResponse.status) return;
647
676
  this.getLocalesData(locale);
648
677
  this.debug.log("SUBSCRIBING TO USER LOCALE STORE");
649
- const skipFetch = initialTranslationsLocale === locale && !!initialTranslations2;
650
- this.translationsLoadingPromise = this.Translations.change(locale, false, skipFetch);
678
+ this.translationsLoadingPromise = this.Translations.change(locale, false);
651
679
  });
652
680
  return validateResponse;
653
681
  }
@@ -1048,10 +1076,16 @@ async function registerContentBlock(contentBlock) {
1048
1076
  return { status: true };
1049
1077
  }
1050
1078
  try {
1051
- const response = await LangsysAppAPI.post(
1052
- "projects/[projectid]/content-blocks",
1053
- contentBlock
1054
- );
1079
+ const response = await LangsysAppAPI.createTranslatableItems([
1080
+ {
1081
+ type: "content_block",
1082
+ custom_id: contentBlock.custom_id,
1083
+ category: contentBlock.category,
1084
+ content: contentBlock.content,
1085
+ label: contentBlock.label,
1086
+ phrases: contentBlock.tokens.map((phrase) => ({ phrase }))
1087
+ }
1088
+ ]);
1055
1089
  if (!response.status) {
1056
1090
  logger.error("Could not save content block", response.errors);
1057
1091
  return { status: false, errors: response.errors };