@onlineapps/cookbook-template-helpers 1.0.15 → 2.0.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 CHANGED
@@ -1,3 +1,14 @@
1
+ > Status: current
2
+ > Owns: the helper functions a cookbook template variable may call
3
+
4
+ <!-- BEGIN GENERATED: library-uniform — regenerate: npx oa-sync-template readme-uniform --all -->
5
+ Uniform: [library/orchestration](../../connector/conn-orch-validator/manifests/library.manifest.json)
6
+
7
+ Duty sections that apply:
8
+
9
+ - `all`: L-MAIN, L-ENGINES, L-TESTS, L-TEST-SCRIPT, L-PACK-TESTS, L-PINS, L-NO-FILE-RANGE, L-CHANGELOG, L-README, L-README-REGION, L-CONSUMER
10
+ <!-- END GENERATED: library-uniform -->
11
+
1
12
  # @onlineapps/cookbook-template-helpers
2
13
 
3
14
  Template helper functions for cookbook variable resolution. Helper functions enable data transformations directly in cookbook template variables.
@@ -49,6 +60,15 @@ Převede file/inline descriptor na string (přes ContentResolver). File stáhne
49
60
  async function file2string(descriptor, context)
50
61
  ```
51
62
 
63
+ ### Helper context — logger
64
+
65
+ Oba descriptor helpery si staví `ContentResolver`, pokud jim v kontextu nepředáš
66
+ hotový `context.contentResolver`. V tom případě je `context.logger` **povinný** a
67
+ musí mít všechny čtyři metody: `info()`, `warn()`, `error()`, `debug()` — přesně
68
+ to, co vyžaduje `@onlineapps/content-resolver` a za ním `@onlineapps/conn-base-storage`.
69
+ Chybějící logger i logger neúplný padají hned v `getContentResolver()` a hláška
70
+ jmenuje chybějící metodu; žádný `console` fallback neexistuje.
71
+
52
72
  ## Usage in Cookbook
53
73
 
54
74
  Helpers jsou k dispozici při resolvování template proměnných:
@@ -91,7 +111,7 @@ if (typeof helperFn !== 'function') {
91
111
  balíček exportuje. Neznámý helper je tvrdá chyba, ne prázdná hodnota.
92
112
 
93
113
  Živý cookbook, který touhle cestou prochází:
94
- [`infra/api_doorman/cookbooks/tester-helpers.json`](../../../infra/api_doorman/cookbooks/tester-helpers.json)
114
+ [`infra/api_doorman/static/cookbooks/tester-helpers.json`](../../../infra/api_doorman/static/cookbooks/tester-helpers.json)
95
115
  — volá `normalizeString`, `webalizeString`, `string2file` i `file2string`.
96
116
 
97
117
  ## Adding a Helper
package/package.json CHANGED
@@ -1,13 +1,17 @@
1
1
  {
2
2
  "name": "@onlineapps/cookbook-template-helpers",
3
- "version": "1.0.15",
3
+ "version": "2.0.1",
4
4
  "description": "Template helper functions for cookbook variable resolution - string2file, file2string, and more",
5
+ "oa": {
6
+ "category": "orchestration"
7
+ },
5
8
  "main": "src/index.js",
6
9
  "scripts": {
7
- "test": "jest",
10
+ "test": "npm run test:unit",
11
+ "test:unit": "jest tests/unit",
8
12
  "test:watch": "jest --watch",
9
13
  "test:coverage": "jest --coverage",
10
- "docs": "jsdoc2md --files src/**/*.js > API.md"
14
+ "docs": "jsdoc2md --files 'src/**/*.js' > API.md.tmp && mv API.md.tmp API.md || (rm -f API.md.tmp; exit 1)"
11
15
  },
12
16
  "keywords": [
13
17
  "cookbook",
@@ -19,13 +23,15 @@
19
23
  "author": "OnlineApps",
20
24
  "license": "PROPRIETARY",
21
25
  "dependencies": {
22
- "@onlineapps/content-resolver": "2.0.1"
26
+ "@onlineapps/content-resolver": "4.0.0",
27
+ "@onlineapps/logger-contract": "1.1.0"
23
28
  },
24
29
  "devDependencies": {
25
- "jest": "29.7.0"
30
+ "jest": "29.7.0",
31
+ "jsdoc-to-markdown": "^8.0.0"
26
32
  },
27
33
  "engines": {
28
- "node": ">=18.0.0"
34
+ "node": ">=24.0.0 <25"
29
35
  },
30
36
  "files": [
31
37
  "src"
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  const ContentResolver = require('@onlineapps/content-resolver');
9
+ const { assertLogger } = require('@onlineapps/logger-contract');
9
10
 
10
11
  /**
11
12
  * Normalize string: remove control/unsafe chars, keep letters (incl. diacritics), numbers,
@@ -66,9 +67,17 @@ function getContentResolver(helperContext) {
66
67
  helperContext.data?.step_id ||
67
68
  null;
68
69
 
69
- if (!helperContext.logger || typeof helperContext.logger.warn !== 'function') {
70
- throw new Error('[cookbook-template-helpers] Helper context logger is required - Expected logger with warn() method');
71
- }
70
+ // The logger goes straight into `ContentResolver`, which demands all four
71
+ // methods (content-resolver src/index.js; conn-base-storage 3.0.0 behind it).
72
+ // Until 2026-09-03 only `warn()` was checked here, so a three-method logger
73
+ // passed this gate and failed one frame down — delayed validation, forbidden
74
+ // by architecture-principles.md §4. Owner confirmation:
75
+ // api/docs/governance/confirmations/connector-logger-contract.md 001.
76
+ assertLogger(
77
+ 'cookbook-template-helpers',
78
+ helperContext.logger,
79
+ 'the resolver this helper builds writes where the service writes'
80
+ );
72
81
 
73
82
  return new ContentResolver({
74
83
  context: { workflow_id, step_id },
@@ -76,8 +85,45 @@ function getContentResolver(helperContext) {
76
85
  });
77
86
  }
78
87
 
88
+ /**
89
+ * The declared type of an inline descriptor's bytes, refused here if it is not
90
+ * one.
91
+ *
92
+ * `string2file()` turns those bytes into an object in storage, and the
93
+ * descriptor it returns declares that object's type. A type nobody stated
94
+ * therefore cannot travel on: the frame below fills the hole from the filename
95
+ * extension, so the object ends up carrying a guess presented as a fact
96
+ * (measured 2026-09-08 on the live path — `{ filename: 'payload.json' }` with no
97
+ * `content_type` came back `application/json`, and `content_type: null` came
98
+ * back `text/plain`).
99
+ *
100
+ * Required input, then: not derived and not defaulted
101
+ * (`architecture-principles.md` §3), and stated by whoever knows what the bytes
102
+ * are — the caller.
103
+ *
104
+ * @private
105
+ * @param {*} contentType - The `content_type` the inline descriptor carries.
106
+ * @throws {Error} If it is not a non-empty string.
107
+ */
108
+ function assertDeclaredContentType(contentType) {
109
+ if (typeof contentType === 'string' && contentType.trim() !== '') {
110
+ return;
111
+ }
112
+
113
+ throw new Error(
114
+ '[string2file] Missing required input - "content_type" is required on an inline descriptor: '
115
+ + 'it is the type written to storage and it is never guessed. '
116
+ + 'Fix: pass content_type (e.g. text/plain, application/json).'
117
+ );
118
+ }
119
+
79
120
  /**
80
121
  * Convert string or inline descriptor to file descriptor (uploads via ContentResolver).
122
+ *
123
+ * An inline descriptor MUST declare `content_type` (see
124
+ * `assertDeclaredContentType`). A raw string declares nothing, so the helper
125
+ * names the file itself and states the type of the file it named.
126
+ *
81
127
  * @param {string|Object} input
82
128
  * @param {Object} context
83
129
  * @returns {Promise<Object>}
@@ -100,6 +146,7 @@ async function string2file(input, context) {
100
146
  if (typeof content !== 'string') {
101
147
  throw new Error('[string2file] Inline descriptor content must be a string');
102
148
  }
149
+ assertDeclaredContentType(input.content_type);
103
150
  return await resolver.createDescriptor(content, {
104
151
  filename: input.filename,
105
152
  content_type: input.content_type,