@nodaro/shared 2.0.2 → 2.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodaro/shared",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "Shared types, model catalog, wire contracts, and structural vocabularies for the Nodaro platform and SDK.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -56,12 +56,15 @@ describe("scraper-actors", () => {
56
56
  }
57
57
  })
58
58
 
59
+ // Values match `STATIC_CREDIT_COSTS` / `model_pricing`; the backend-side guard
60
+ // `shared-credit-table-sync.test.ts` is what keeps the two equal. This one only
61
+ // pins that every SKU is present and priced.
59
62
  it("credit costs include bare fallback + every composite SKU", () => {
60
- expect(SCRAPER_CREDIT_COSTS["web-scrape"]).toBe(2)
61
- expect(SCRAPER_CREDIT_COSTS["web-scrape:google-search"]).toBe(3)
62
- expect(SCRAPER_CREDIT_COSTS["web-scrape:content-crawler"]).toBe(1)
63
- expect(SCRAPER_CREDIT_COSTS["web-scrape:content-crawler:site"]).toBe(5)
64
- expect(SCRAPER_CREDIT_COSTS["web-scrape:instagram"]).toBe(1)
65
- expect(SCRAPER_CREDIT_COSTS["web-scrape:tiktok"]).toBe(1)
63
+ expect(SCRAPER_CREDIT_COSTS["web-scrape"]).toBe(20)
64
+ expect(SCRAPER_CREDIT_COSTS["web-scrape:google-search"]).toBe(30)
65
+ expect(SCRAPER_CREDIT_COSTS["web-scrape:content-crawler"]).toBe(10)
66
+ expect(SCRAPER_CREDIT_COSTS["web-scrape:content-crawler:site"]).toBe(50)
67
+ expect(SCRAPER_CREDIT_COSTS["web-scrape:instagram"]).toBe(10)
68
+ expect(SCRAPER_CREDIT_COSTS["web-scrape:tiktok"]).toBe(10)
66
69
  })
67
70
  })
@@ -144,11 +144,14 @@ export interface ModelRecommendation {
144
144
  export const MODEL_RECOMMENDATIONS: readonly ModelRecommendation[] = [
145
145
  // image
146
146
  { intent: "best for typography / logos / text-heavy", modelIds: ["nano-banana-pro", "gpt-image-2"], note: "Nano Banana Pro for diagrams / complex text; GPT Image 2 for logos and short copy." },
147
- { intent: "cheapest realistic image", modelIds: ["z-image", "qwen", "imagen4-fast"], note: "Z-Image is the cheapest at 1 credit. Qwen / Imagen4 Fast for slightly higher quality." },
147
+ // Notes name the RANKING, not the price the price sits in the generated
148
+ // table directly below them and in `pricing`, so restating it here just
149
+ // creates a copy that rots (this one said "1 credit" long after it was 2).
150
+ { intent: "cheapest realistic image", modelIds: ["z-image", "qwen", "imagen4-fast"], note: "Z-Image is the cheapest. Qwen / Imagen4 Fast for slightly higher quality." },
148
151
  { intent: "highest fidelity image", modelIds: ["nano-banana-pro", "imagen4-ultra", "flux-flex"], note: "Pick by family preference; all three are premium tiers." },
149
152
  { intent: "image edit / restyle", modelIds: ["flux-kontext", "ideogram-remix", "seedream-5-pro-i2i"], note: "Flux Kontext preserves identity; Ideogram Remix is character-aware; Seedream 5 Pro for instruction-based edits (5 Lite is the budget option)." },
150
153
  { intent: "highest-resolution image (4K / 8K)", modelIds: ["topaz-image-upscale", "nano-banana-pro", "gpt-image-2"], note: "Generate at native then Topaz upscale for 8K." },
151
- { intent: "background removal / cutout", modelIds: ["recraft-remove-bg"], note: "1 credit, no prompt needed." },
154
+ { intent: "background removal / cutout", modelIds: ["recraft-remove-bg"], note: "Cheap, no prompt needed." },
152
155
  // video
153
156
  { intent: "best cinematic video", modelIds: ["veo3", "kling-3.0", "seedance-2"], note: "VEO 3.1 Quality for premium narrative; Kling 3.0 for music-synced motion; Seedance 2 for reference-driven consistency." },
154
157
  { intent: "cheap batch video clips", modelIds: ["veo3.1", "wan-turbo", "bytedance-lite"], note: "VEO 3.1 Fast is the best price/quality balance with native audio." },
@@ -72,12 +72,18 @@ export const TIER_PIPELINE_PARALLELISM: Record<string, number> = {
72
72
  }
73
73
 
74
74
  // Tier → default hard cost cap when max_cost_credits omitted (Architecture §6.6.3)
75
+ //
76
+ // These are a FRACTION OF THE TIER'S GRANT, so they move with `TIER_CREDITS`:
77
+ // the 2026-07-30 ×10 re-denomination multiplied every grant, and leaving these
78
+ // behind would have silently tightened each cap tenfold — a basic-tier pipeline
79
+ // would abort at 300 credits out of a 4,500-credit grant, i.e. 6% of the plan
80
+ // the user paid for, instead of the intended two-thirds.
75
81
  export const TIER_MAX_PIPELINE_COST_CREDITS: Record<string, number> = {
76
82
  free: 0,
77
- basic: 300,
78
- standard: 800,
79
- pro: 2000,
80
- business: 5000,
83
+ basic: 3000,
84
+ standard: 8000,
85
+ pro: 20000,
86
+ business: 50000,
81
87
  }
82
88
 
83
89
  // Per-stage soft timeout (matches workflow-orchestration)
@@ -16,15 +16,20 @@ export const SCRAPER_ACTOR_LABELS: Record<ScraperActorId, string> = {
16
16
  "rss": "RSS Feed",
17
17
  }
18
18
 
19
- /** Credit costs per composite SKU — must stay in sync with STATIC_CREDIT_COSTS in backend. */
19
+ /** Credit costs per composite SKU — must stay in sync with STATIC_CREDIT_COSTS in backend.
20
+ *
21
+ * "Must stay in sync" was doing no work: these were left at the pre-2026-07-30
22
+ * credit base while the backend moved, so every SKU here read a tenth of the
23
+ * real price. Values below are copied from `model_pricing`, which is what the
24
+ * user is actually charged. */
20
25
  export const SCRAPER_CREDIT_COSTS: Record<string, number> = {
21
- "web-scrape": 2,
22
- "web-scrape:google-search": 3,
23
- "web-scrape:content-crawler": 1,
24
- "web-scrape:content-crawler:site": 5,
25
- "web-scrape:instagram": 1,
26
- "web-scrape:tiktok": 1,
27
- "web-scrape:rss": 1,
26
+ "web-scrape": 20,
27
+ "web-scrape:google-search": 30,
28
+ "web-scrape:content-crawler": 10,
29
+ "web-scrape:content-crawler:site": 50,
30
+ "web-scrape:instagram": 10,
31
+ "web-scrape:tiktok": 10,
32
+ "web-scrape:rss": 10,
28
33
  }
29
34
 
30
35
  export function isScraperActor(value: unknown): value is ScraperActorId {