@dumbql/ssr 0.0.1 → 0.0.2-alpha.1

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/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # @dumbql/ssr
2
+
3
+ Server-Side Rendering helpers for DumbQL. Transfers GraphQL cache from server to browser using Angular's `TransferState`.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @dumbql/ssr
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { TransferCacheService, SsrStreamService } from '@dumbql/ssr';
15
+
16
+ // On server: serialize the cache after all queries
17
+ const transferCache = inject(TransferCacheService);
18
+ const cache = inject(CacheService);
19
+ transferCache.save(cache); // stores in TransferState
20
+
21
+ // On browser: restore the cache before any query
22
+ transferCache.restore(cache); // loads from TransferState
23
+ ```
24
+
25
+ ## Streaming
26
+
27
+ ```typescript
28
+ const stream = inject(SsrStreamService);
29
+ stream.writeChunked('myKey', data); // server
30
+ const data = stream.readChunked('myKey'); // browser
31
+ ```
32
+
33
+ ## API
34
+
35
+ | Export | Description |
36
+ |--------|-------------|
37
+ | `TransferCacheService` | Saves/restores full cache snapshot to/from `TransferState` |
38
+ | `SsrStreamService` | Chunked key-value streaming via `TransferState` |
39
+ | `SSR_STREAM_KEY` | Injection token for config (prefix, chunk size) |
40
+ | `SsrStreamConfig` | `{ key?: string, chunkSize?: number }` |
41
+
42
+ ## Dependencies
43
+
44
+ `@angular/common`, `@angular/core`, `@dumbql/cache`, `rxjs`
@@ -1 +1 @@
1
- {"version":3,"file":"dumbql-ssr.mjs","sources":["../../../../projects/dumbql/ssr/src/lib/ssr-stream.ts","../../../../projects/dumbql/ssr/src/lib/transfer-cache.service.ts","../../../../projects/dumbql/ssr/src/dumbql-ssr.ts"],"sourcesContent":["import { Injectable, inject, InjectionToken, TransferState, makeStateKey } from '@angular/core';\n\nexport const SSR_STREAM_KEY = new InjectionToken<string>('SSR_STREAM_KEY');\n\nexport interface SsrStreamConfig {\n /** Key prefix for TransferState */\n key?: string;\n /** Chunk size for progressive loading (bytes) */\n chunkSize?: number;\n}\n\n/**\n * Service for progressive SSR transfer of GraphQL data.\n * Splits large payloads into chunks for faster TTFB.\n */\n@Injectable({ providedIn: 'root' })\nexport class SsrStreamService {\n private readonly transferState = inject(TransferState, { optional: true });\n private readonly config: SsrStreamConfig;\n\n constructor() {\n \tthis.config = (inject(SSR_STREAM_KEY, { optional: true }) as SsrStreamConfig) ?? {};\n }\n\n /** Serialize data to TransferState in chunks */\n writeChunked(key: string, data: unknown): void {\n \tif (!this.transferState) return;\n \tconst stateKey = makeStateKey<unknown>(`${this.config.key ?? 'gql'}_${key}`);\n \tthis.transferState.set(stateKey, data);\n }\n\n /** Read chunked data from TransferState */\n readChunked<T>(key: string): T | undefined {\n \tif (!this.transferState) return undefined;\n \tconst stateKey = makeStateKey<T | undefined>(`${this.config.key ?? 'gql'}_${key}`);\n \treturn this.transferState.get(stateKey, undefined);\n }\n\n /** Clear all GQL-related TransferState entries */\n clear(): void {\n \t// TransferState doesn't expose keys, so this is a no-op in Angular\n }\n}\n","import { Injectable, inject, PLATFORM_ID } from '@angular/core';\nimport { isPlatformServer, isPlatformBrowser } from '@angular/common';\nimport { SsrStreamService } from './ssr-stream';\nimport { type CacheService } from '@dumbql/cache';\n\n@Injectable({ providedIn: 'root' })\nexport class TransferCacheService {\n private readonly platformId = inject(PLATFORM_ID);\n private readonly streamSvc = inject(SsrStreamService);\n\n /** Save cache state for transfer to browser */\n save(cache: CacheService): void {\n \tif (!isPlatformServer(this.platformId)) return;\n \tthis.streamSvc.writeChunked('cache', cache.serialize());\n }\n\n /** Restore cache state from SSR transfer */\n restore(cache: CacheService): boolean {\n \tif (!isPlatformBrowser(this.platformId)) return false;\n \tconst data = this.streamSvc.readChunked<string>('cache');\n \tif (!data) return false;\n \ttry {\n \t\tcache.deserialize(data);\n \t\treturn true;\n \t} catch {\n \t\treturn false;\n \t}\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dumbql-ssr.mjs","sources":["../../../../projects/dumbql/ssr/src/lib/ssr-stream.ts","../../../../projects/dumbql/ssr/src/lib/transfer-cache.service.ts","../../../../projects/dumbql/ssr/src/dumbql-ssr.ts"],"sourcesContent":["import { Injectable, inject, InjectionToken, TransferState, makeStateKey } from '@angular/core';\n\nexport const SSR_STREAM_KEY = new InjectionToken<string>('SSR_STREAM_KEY');\n\nexport interface SsrStreamConfig {\n /** Key prefix for TransferState */\n key?: string;\n /** Chunk size for progressive loading (bytes) */\n chunkSize?: number;\n}\n\n/**\n * Service for progressive SSR transfer of GraphQL data.\n * Splits large payloads into chunks for faster TTFB.\n */\n@Injectable({ providedIn: 'root' })\nexport class SsrStreamService {\n private readonly transferState = inject(TransferState, { optional: true });\n private readonly config: SsrStreamConfig;\n\n constructor() {\n \tthis.config = (inject(SSR_STREAM_KEY, { optional: true }) as SsrStreamConfig) ?? {};\n }\n\n /** Serialize data to TransferState in chunks */\n writeChunked(key: string, data: unknown): void {\n \tif (!this.transferState) return;\n \tconst stateKey = makeStateKey<unknown>(`${this.config.key ?? 'gql'}_${key}`);\n \tthis.transferState.set(stateKey, data);\n }\n\n /** Read chunked data from TransferState */\n readChunked<T>(key: string): T | undefined {\n \tif (!this.transferState) return undefined;\n \tconst stateKey = makeStateKey<T | undefined>(`${this.config.key ?? 'gql'}_${key}`);\n \treturn this.transferState.get(stateKey, undefined);\n }\n\n /** Clear all GQL-related TransferState entries */\n clear(): void {\n \t// TransferState doesn't expose keys, so this is a no-op in Angular\n }\n}\n","import { Injectable, inject, PLATFORM_ID } from '@angular/core';\nimport { isPlatformServer, isPlatformBrowser } from '@angular/common';\nimport { SsrStreamService } from './ssr-stream';\nimport { type CacheService } from '@dumbql/cache/angular';\n\n@Injectable({ providedIn: 'root' })\nexport class TransferCacheService {\n private readonly platformId = inject(PLATFORM_ID);\n private readonly streamSvc = inject(SsrStreamService);\n\n /** Save cache state for transfer to browser */\n save(cache: CacheService): void {\n \tif (!isPlatformServer(this.platformId)) return;\n \tthis.streamSvc.writeChunked('cache', cache.serialize());\n }\n\n /** Restore cache state from SSR transfer */\n restore(cache: CacheService): boolean {\n \tif (!isPlatformBrowser(this.platformId)) return false;\n \tconst data = this.streamSvc.readChunked<string>('cache');\n \tif (!data) return false;\n \ttry {\n \t\tcache.deserialize(data);\n \t\treturn true;\n \t} catch {\n \t\treturn false;\n \t}\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dumbql/ssr",
3
- "version": "0.0.1",
3
+ "version": "0.0.2-alpha.1",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^22.0.0",
6
6
  "@angular/core": "^22.0.0",
@@ -1,4 +1,4 @@
1
- import { CacheService } from '@dumbql/cache';
1
+ import { CacheService } from '@dumbql/cache/angular';
2
2
  import * as i0 from '@angular/core';
3
3
  import { InjectionToken } from '@angular/core';
4
4