toga-ai 1.0.603 → 1.0.604
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.
|
@@ -7,7 +7,7 @@ client: shared
|
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
9
|
updated: 2026-08-03
|
|
10
|
-
owners: ["jcardinal", "bala", "mhammontree"]
|
|
10
|
+
owners: ["jcardinal", "bala", "mhammontree", "apeterson"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model/Client/EmailTemplate.php
|
|
13
13
|
- _underscore/Model/Client/EmailTemplateOutgoingEmailAddress.php
|
|
@@ -98,6 +98,16 @@ can keep using `sendEmail($api, ...)`.
|
|
|
98
98
|
2026-06-15 the only entry point was `sendEmail(&$api, ...)`, so callers with no API
|
|
99
99
|
context faked one: `$api = (object)['client' => (object)['clientIdentifier' => …]]`.
|
|
100
100
|
That hack is obsolete — pass the identifier to `send()` instead.
|
|
101
|
+
- **⚠ Template vars MUST be spread into the variadic, never passed as a bare array.** Both
|
|
102
|
+
`sendEmail(&$api, $uuid, $to, $cc, $bcc, ...$args)` and `send(...)` collect the template
|
|
103
|
+
variables via `...$args`. Pass them **spread** so PHP 8.1+ named-argument collection yields
|
|
104
|
+
string keys/string values (`sendEmail($api, $uuid, $to, [], [], ...['userName'=>$name, ...])`
|
|
105
|
+
→ `$args = ['userName'=>$name, ...]`). Passing the map as a single positional argument
|
|
106
|
+
(`sendEmail($api, $uuid, $to, [], [], $vars)`) makes `$args = [0 => [...]]` — a numeric key
|
|
107
|
+
whose value is an *array*. `replaceTemplateVariables()` then runs `str_replace('{0}', <array>, …)`
|
|
108
|
+
→ `TypeError: str_replace(): Argument #2 must be of type string, array given`, surfacing as a
|
|
109
|
+
production 500 / **EO-1**. `Model/Compass/*` gets this right (spread); the four `Model/Quad/*`
|
|
110
|
+
call sites were copied from Compass but dropped the `...` — fixed 2026-08-18.
|
|
101
111
|
- **`sendEmail()`'s signature is load-bearing for scripted APIs** — the Record Script engine
|
|
102
112
|
(`api2/Component/Api/V2/V2.php`, ~line 3594) calls the method with `api` as a named
|
|
103
113
|
argument, so the first param must stay `&$api`. Do not "clean it up" by removing it.
|
|
@@ -151,6 +161,12 @@ worker method) in-process instead.
|
|
|
151
161
|
|
|
152
162
|
## Change history
|
|
153
163
|
|
|
164
|
+
- 2026-08-18 — Fixed the Quad order-approval/rejection emails' production 500
|
|
165
|
+
(`str_replace(): Argument #2 must be string`, EO-1): the four `Model/Quad/ApprovalDecision.php`
|
|
166
|
+
+ `Model/Quad/SalesOrder.php` call sites passed the template-vars map as a bare positional
|
|
167
|
+
array, so `...$args` collected `[0 => [...]]` and `replaceTemplateVariables()` fed an array to
|
|
168
|
+
`str_replace`. Fix = spread the array (`...[...]`) to match the working `Model/Compass/*`
|
|
169
|
+
pattern. Added the **"template vars must be spread, never a bare array"** gotcha. (apeterson)
|
|
154
170
|
- 2026-08-03 — Refined the `CharSet` gotcha: the **transmit** side doesn't set it either, so the
|
|
155
171
|
effective wire charset is **iso-8859-1**, and a body that needs accents should escape with
|
|
156
172
|
`htmlentities($v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', false)` (details on
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
| [API Payload Interceptors (metadata-registered prePost/postPut model hooks)](features/api-payload-interceptors.md) | A `_Model`'s `prePost()` / `postPost()` / `prePut()` / `postPut()` hooks are **not** called by the model. | api2/Component/Api/V2/V2.php, api2/Controller/Index.php, _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Compass/PurchaseOrder.php, _underscore/Model/Elite/SalesOrder.php, _underscore/Model/Elite/ServiceRequest.php, _underscore/Model/Compass/SalesOrder.php, _underscore/Model/Compass/SalesOrderItem.php, dbchanges2/Core/2026-06-30a - ItemFulfillmentStageDefaultInterceptor.sql, dbchanges2/Core/2026-08-06a - Service request and sales order payload interceptors.sql, dbchanges2/Client_Compass/2026-08-06 - RemoveBrokenSalesOrderItemPostPostInterceptor.sql, dbchanges2/Client_Compass/2026-08-14a - AddSalesOrderInactiveStandaloneItemPreInterceptors.sql, dbchanges2/Client_CompassCanada/2026-08-14a - AddSalesOrderInactiveStandaloneItemPreInterceptors.sql |
|
|
7
7
|
| [Multi-Client (Cross-Client) Data Retrieval](features/cross-client-data-retrieval.md) | A single authenticated V2 GET listing can return records across **many** clients (designed for 1000+) that the caller is entitled to, honoring **each target cli | api2/Component/Api/CrossClient/CrossClient.php, api2/Component/Api/V2/V2.php, api2/Controller/Index.php, _underscore/Model/Cache/Table.php, _underscore/Model/Cache/Tables/Client.php, _underscore/Model/Core/Record.php, worker2/Worker/Platform/Cache.php, worker2/Controller/Index.php, worker2/_.php, dbchanges2/Cache/2026-06-30a - MultiClientCacheTables.sql, dbchanges2/Core/2026-06-30b - CacheClusterRegistrationAndRecordTtl.sql, dbchanges2/Core/2026-07-27a - PlatformCacheCleanCron.sql |
|
|
8
8
|
| [Encrypted-User-UUID Auth Handoff (/auth/encrypted-user-uuid)](features/encrypted-user-uuid-auth-handoff.md) | `POST /auth/encrypted-user-uuid` is the intended **cross-client / SSO-handoff identity mechanism**: given an encrypted `{client, user}` UUID pair, it mints a fr | api2/Component/Api/CrossClient/CrossClient.php |
|
|
9
|
-
| [ENVIRONMENT (not the EB environment name) decides the _underscore branch and Config file](features/environment-variable-drives-underscore-branch.md) | An api2 Elastic Beanstalk instance decides **which `_underscore` branch it clones** and **which `Config/<env>.ini` it loads** from the EB environment property * | api2/.ebextensions/git.php, api2/.ebextensions/php_include_underscore.config, api2/.ebextensions/git.sandbox-dev.json, api2/Config/beta.ini, api2/Config/sandbox-dev.ini, api2/Component/Api/V2/V2.php |
|
|
9
|
+
| [ENVIRONMENT (not the EB environment name) decides the _underscore branch and Config file](features/environment-variable-drives-underscore-branch.md) | An api2 Elastic Beanstalk instance decides **which `_underscore` branch it clones** and **which `Config/<env>.ini` it loads** from the EB environment property * | api2/.ebextensions/git.php, api2/.ebextensions/php_include_underscore.config, api2/.ebextensions/git.sandbox-dev.json, api2/.ebextensions/git.sandbox-client.json, api2/Config/beta.ini, api2/Config/sandbox-dev.ini, api2/Component/Api/V2/V2.php |
|
|
10
10
|
| [Health-check endpoint (/health liveness short-circuit)](features/health-check-endpoint.md) | `_Controller_Index::api()` short-circuits **liveness/health-probe** requests to an HTTP 200 **before** any routing, DB bootstrap, or V2 engine work runs. | api2/Controller/Index.php |
|
|
11
11
|
| [Language Translation Layer (audience.language + sidecar tables)](features/language-translation-layer.md) | Serves the same TOGa data (Item title/description/longDescription, plus item **feature** text — `Features.name`, `ItemCategoryFeatureGroups.name`, `ItemFeatures | api2/Component/Api/V2/V2.php, api2/Component/Api/V2/Response/Response.php, _underscore/Model/Core/Setting.php, _underscore/Model/Core/RecordField.php, _underscore/Model/Core/DefaultGlobalSetting.php, _underscore/Model/Client/ItemTranslation.php, _underscore/Model/Client/FeatureTranslation.php, _underscore/Model/Client/ItemCategoryFeatureGroupTranslation.php, _underscore/Model/Client/ItemFeatureTranslation.php, dbchanges2/Client/2026-06-23a - ItemTranslations.sql, dbchanges2/Client/2026-06-23b - ItemTranslationsAcl.sql, dbchanges2/Client/2026-07-13a - FeatureTranslations.sql, dbchanges2/Client/2026-07-13b - FeatureTranslationsAcl.sql, dbchanges2/Core/2026-06-23a - RecordFieldsTranslationColumn.sql, dbchanges2/Core/2026-06-23b - ItemTranslationsRecord.sql, dbchanges2/Core/2026-07-13 - FeatureTranslationsRecord.sql |
|
|
12
12
|
| [/auth/login resolves the client from the email domain, not the Bearer token (cross-client user path)](features/login-cross-client-user-resolution.md) | `POST /v2/auth/login` (email/password user login) can silently swap the target client mid-request. | api2/Component/Api/V2/V2.php, _underscore/String.php |
|
|
@@ -7,11 +7,12 @@ client: shared
|
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
9
|
updated: 2026-08-06
|
|
10
|
-
owners: ["bala", "mhammontree"]
|
|
10
|
+
owners: ["bala", "mhammontree", "apeterson"]
|
|
11
11
|
files:
|
|
12
12
|
- api2/.ebextensions/git.php
|
|
13
13
|
- api2/.ebextensions/php_include_underscore.config
|
|
14
14
|
- api2/.ebextensions/git.sandbox-dev.json
|
|
15
|
+
- api2/.ebextensions/git.sandbox-client.json
|
|
15
16
|
- api2/Config/beta.ini
|
|
16
17
|
- api2/Config/sandbox-dev.ini
|
|
17
18
|
- api2/Component/Api/V2/V2.php
|
|
@@ -116,12 +117,36 @@ one.
|
|
|
116
117
|
`_underscore`. (Contrast: the 1.0 **tools** app works cleanly because its helper *and* its config
|
|
117
118
|
live in the same repo, and it clones `library` from a **fixed** branch, `_production`, rather
|
|
118
119
|
than an `ENVIRONMENT`-derived one.)
|
|
120
|
+
- **⚠ A `git.<env>.json` `"branch"` key can pin a tier to the WRONG `_underscore` branch, silently.**
|
|
121
|
+
When a code fix pushed to a branch does not appear after an api2 deploy, before debugging the
|
|
122
|
+
code verify which branch that EB environment's `.ebextensions/git.<env>.json` actually clones:
|
|
123
|
+
a present `"branch"` value overrides the `'_' . strtolower(ENVIRONMENT)` default. **Concrete
|
|
124
|
+
(fixed 2026-08-18):** `git.sandbox-client.json` had `"branch": "_production"`, so the
|
|
125
|
+
`sandbox-client` environment ran `_underscore` from `_production` — never `_sandbox-client` —
|
|
126
|
+
which is why fixes merged to `_sandbox-client` never showed up there. Confirmed two ways: the
|
|
127
|
+
config file value, and live runtime behavior matching `_production` (unfixed) rather than
|
|
128
|
+
`_sandbox-client` (fixed). Fix = remove the `"branch"` key so it falls back to `_sandbox-client`.
|
|
129
|
+
- **Deploy path is build-time, so a git push alone does not update running instances.** The
|
|
130
|
+
`_underscore` clone happens in the prebuild hook at build time: commit the fix on the feature
|
|
131
|
+
branch, merge that branch into the deploy-channel branch (`_` + `ENVIRONMENT`, e.g.
|
|
132
|
+
`_sandbox-client`), push, **then redeploy the EB environment** to re-run the clone.
|
|
133
|
+
- **⚠ SECURITY — every `.ebextensions/git.*.json` carries a plaintext GitHub PAT** committed in
|
|
134
|
+
the repo (used to clone `_underscore`). Pre-existing leak; treat the committed tokens as
|
|
135
|
+
compromised, rotate, and move them to EB environment properties / SSM. Do **not** copy the token
|
|
136
|
+
value anywhere — this note records only that the credential lives in these files.
|
|
119
137
|
- **Duplicate integration code is the trap this creates.** When the same capability is needed in
|
|
120
138
|
both tiers it must exist twice (once per framework) — keep the credential/config location
|
|
121
139
|
documented in both places so a rotation updates both.
|
|
122
140
|
|
|
123
141
|
## Change history
|
|
124
142
|
|
|
143
|
+
- 2026-08-18 — Recorded a second concrete `"branch"`-pin trap: `git.sandbox-client.json` pinned
|
|
144
|
+
`"branch": "_production"`, so the `sandbox-client` EB environment cloned `_underscore` from
|
|
145
|
+
`_production` and never received `_sandbox-client` merges (confirmed via both the config value and
|
|
146
|
+
live runtime matching the unfixed `_production` code); fix = drop the `"branch"` key. Added the
|
|
147
|
+
general diagnostic ("fix not appearing after deploy → check `git.<env>.json` branch pin first"),
|
|
148
|
+
the build-time deploy note (merge into `_`+ENVIRONMENT then redeploy — a push alone is inert),
|
|
149
|
+
and the ⚠ plaintext-GitHub-PAT-in-`git.*.json` security gotcha (location only). (apeterson)
|
|
125
150
|
- 2026-08-06 — TRUE-80282 deploy: independently re-confirmed the mapping from a second tier
|
|
126
151
|
(`api.beta.togahub.com` = `ENVIRONMENT=beta` → `Config/beta.ini` → branch `_beta`) at a cost of two
|
|
127
152
|
deploy cycles, and recorded **why** the branch derives: there is deliberately **no
|
package/package.json
CHANGED