@workos/oagen-emitters 0.2.1 → 0.4.0
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/.husky/pre-commit +1 -0
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +15 -0
- package/README.md +129 -0
- package/dist/index.d.mts +13 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +14549 -3385
- package/dist/index.mjs.map +1 -1
- package/docs/sdk-architecture/dotnet.md +336 -0
- package/docs/sdk-architecture/go.md +338 -0
- package/docs/sdk-architecture/php.md +315 -0
- package/docs/sdk-architecture/python.md +511 -0
- package/oagen.config.ts +328 -2
- package/package.json +9 -5
- package/scripts/generate-php.js +13 -0
- package/scripts/git-push-with-published-oagen.sh +21 -0
- package/smoke/sdk-dotnet.ts +45 -12
- package/smoke/sdk-go.ts +116 -42
- package/smoke/sdk-php.ts +28 -26
- package/smoke/sdk-python.ts +5 -2
- package/src/dotnet/client.ts +89 -0
- package/src/dotnet/enums.ts +323 -0
- package/src/dotnet/fixtures.ts +236 -0
- package/src/dotnet/index.ts +246 -0
- package/src/dotnet/manifest.ts +36 -0
- package/src/dotnet/models.ts +344 -0
- package/src/dotnet/naming.ts +330 -0
- package/src/dotnet/resources.ts +622 -0
- package/src/dotnet/tests.ts +693 -0
- package/src/dotnet/type-map.ts +201 -0
- package/src/dotnet/wrappers.ts +186 -0
- package/src/go/client.ts +141 -0
- package/src/go/enums.ts +196 -0
- package/src/go/fixtures.ts +212 -0
- package/src/go/index.ts +84 -0
- package/src/go/manifest.ts +36 -0
- package/src/go/models.ts +254 -0
- package/src/go/naming.ts +179 -0
- package/src/go/resources.ts +827 -0
- package/src/go/tests.ts +751 -0
- package/src/go/type-map.ts +82 -0
- package/src/go/wrappers.ts +261 -0
- package/src/index.ts +4 -0
- package/src/kotlin/client.ts +53 -0
- package/src/kotlin/enums.ts +162 -0
- package/src/kotlin/index.ts +92 -0
- package/src/kotlin/manifest.ts +55 -0
- package/src/kotlin/models.ts +395 -0
- package/src/kotlin/naming.ts +223 -0
- package/src/kotlin/overrides.ts +25 -0
- package/src/kotlin/resources.ts +667 -0
- package/src/kotlin/tests.ts +1019 -0
- package/src/kotlin/type-map.ts +123 -0
- package/src/kotlin/wrappers.ts +168 -0
- package/src/node/client.ts +128 -115
- package/src/node/enums.ts +9 -0
- package/src/node/errors.ts +37 -232
- package/src/node/field-plan.ts +726 -0
- package/src/node/fixtures.ts +9 -1
- package/src/node/index.ts +3 -9
- package/src/node/models.ts +178 -21
- package/src/node/naming.ts +49 -111
- package/src/node/resources.ts +527 -397
- package/src/node/sdk-errors.ts +41 -0
- package/src/node/tests.ts +69 -19
- package/src/node/type-map.ts +4 -2
- package/src/node/utils.ts +13 -71
- package/src/node/wrappers.ts +151 -0
- package/src/php/client.ts +179 -0
- package/src/php/enums.ts +67 -0
- package/src/php/errors.ts +9 -0
- package/src/php/fixtures.ts +181 -0
- package/src/php/index.ts +96 -0
- package/src/php/manifest.ts +36 -0
- package/src/php/models.ts +310 -0
- package/src/php/naming.ts +279 -0
- package/src/php/resources.ts +636 -0
- package/src/php/tests.ts +609 -0
- package/src/php/type-map.ts +90 -0
- package/src/php/utils.ts +18 -0
- package/src/php/wrappers.ts +152 -0
- package/src/python/client.ts +345 -0
- package/src/python/enums.ts +313 -0
- package/src/python/fixtures.ts +196 -0
- package/src/python/index.ts +95 -0
- package/src/python/manifest.ts +38 -0
- package/src/python/models.ts +688 -0
- package/src/python/naming.ts +189 -0
- package/src/python/resources.ts +1322 -0
- package/src/python/tests.ts +1335 -0
- package/src/python/type-map.ts +93 -0
- package/src/python/wrappers.ts +191 -0
- package/src/shared/model-utils.ts +472 -0
- package/src/shared/naming-utils.ts +154 -0
- package/src/shared/non-spec-services.ts +54 -0
- package/src/shared/resolved-ops.ts +109 -0
- package/src/shared/wrapper-utils.ts +70 -0
- package/test/dotnet/client.test.ts +121 -0
- package/test/dotnet/enums.test.ts +193 -0
- package/test/dotnet/errors.test.ts +9 -0
- package/test/dotnet/manifest.test.ts +82 -0
- package/test/dotnet/models.test.ts +260 -0
- package/test/dotnet/resources.test.ts +255 -0
- package/test/dotnet/tests.test.ts +202 -0
- package/test/go/client.test.ts +92 -0
- package/test/go/enums.test.ts +132 -0
- package/test/go/errors.test.ts +9 -0
- package/test/go/models.test.ts +265 -0
- package/test/go/resources.test.ts +408 -0
- package/test/go/tests.test.ts +143 -0
- package/test/kotlin/models.test.ts +135 -0
- package/test/kotlin/tests.test.ts +176 -0
- package/test/node/client.test.ts +92 -12
- package/test/node/enums.test.ts +2 -0
- package/test/node/errors.test.ts +2 -41
- package/test/node/models.test.ts +2 -0
- package/test/node/naming.test.ts +23 -0
- package/test/node/resources.test.ts +315 -84
- package/test/node/serializers.test.ts +3 -1
- package/test/node/type-map.test.ts +11 -0
- package/test/php/client.test.ts +95 -0
- package/test/php/enums.test.ts +173 -0
- package/test/php/errors.test.ts +9 -0
- package/test/php/models.test.ts +497 -0
- package/test/php/resources.test.ts +682 -0
- package/test/php/tests.test.ts +185 -0
- package/test/python/client.test.ts +200 -0
- package/test/python/enums.test.ts +228 -0
- package/test/python/errors.test.ts +16 -0
- package/test/python/manifest.test.ts +74 -0
- package/test/python/models.test.ts +716 -0
- package/test/python/resources.test.ts +617 -0
- package/test/python/tests.test.ts +202 -0
- package/src/node/common.ts +0 -273
- package/src/node/config.ts +0 -71
- package/src/node/serializers.ts +0 -746
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# PHP SDK Architecture
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
A PHP 8.2+ SDK using readonly classes, backed enums, Guzzle for HTTP, and PHPUnit for testing. PSR-4 autoloading with Composer.
|
|
6
|
+
|
|
7
|
+
## Naming Conventions
|
|
8
|
+
|
|
9
|
+
| IR Name | PHP Convention | Example |
|
|
10
|
+
| --------------------- | -------------- | ----------------- |
|
|
11
|
+
| `UserProfile` (class) | PascalCase | `UserProfile` |
|
|
12
|
+
| `UserProfile` (file) | PascalCase.php | `UserProfile.php` |
|
|
13
|
+
| `listUsers` (method) | camelCase | `listUsers` |
|
|
14
|
+
| `user_id` (field) | camelCase | `userId` |
|
|
15
|
+
| `ACTIVE` (enum case) | PascalCase | `Active` |
|
|
16
|
+
|
|
17
|
+
## Type Mapping
|
|
18
|
+
|
|
19
|
+
| IR TypeRef | PHP Type Hint | PHPDoc Type |
|
|
20
|
+
| -------------------- | -------------------- | -------------------- |
|
|
21
|
+
| `string` | `string` | `string` |
|
|
22
|
+
| `string` (date) | `string` | `string` |
|
|
23
|
+
| `string` (date-time) | `\DateTimeImmutable` | `\DateTimeImmutable` |
|
|
24
|
+
| `string` (uuid) | `string` | `string` |
|
|
25
|
+
| `string` (binary) | `string` | `string` |
|
|
26
|
+
| `integer` | `int` | `int` |
|
|
27
|
+
| `number` | `float` | `float` |
|
|
28
|
+
| `boolean` | `bool` | `bool` |
|
|
29
|
+
| `unknown` | `mixed` | `mixed` |
|
|
30
|
+
| `array<T>` | `array` | `array<T>` |
|
|
31
|
+
| `model Foo` | `Foo` | `Foo` |
|
|
32
|
+
| `enum Foo` | `Foo` | `Foo` |
|
|
33
|
+
| `nullable<T>` | `?T` | `T\|null` |
|
|
34
|
+
| `union<A,B>` | `A\|B` | `A\|B` |
|
|
35
|
+
| `map<string,V>` | `array` | `array<string, V>` |
|
|
36
|
+
| `literal "foo"` | `string` | `string` |
|
|
37
|
+
|
|
38
|
+
## Model Pattern
|
|
39
|
+
|
|
40
|
+
Readonly classes with constructor promotion, `fromArray()` factory, and `toArray()` serialization:
|
|
41
|
+
|
|
42
|
+
```php
|
|
43
|
+
<?php
|
|
44
|
+
|
|
45
|
+
namespace WorkOS\Models;
|
|
46
|
+
|
|
47
|
+
readonly class Organization implements \JsonSerializable
|
|
48
|
+
{
|
|
49
|
+
public function __construct(
|
|
50
|
+
public string $id,
|
|
51
|
+
public string $name,
|
|
52
|
+
public ?string $slug = null,
|
|
53
|
+
public ?\DateTimeImmutable $createdAt = null,
|
|
54
|
+
) {}
|
|
55
|
+
|
|
56
|
+
public static function fromArray(array $data): static
|
|
57
|
+
{
|
|
58
|
+
return new static(
|
|
59
|
+
id: $data['id'],
|
|
60
|
+
name: $data['name'],
|
|
61
|
+
slug: $data['slug'] ?? null,
|
|
62
|
+
createdAt: isset($data['created_at'])
|
|
63
|
+
? new \DateTimeImmutable($data['created_at'])
|
|
64
|
+
: null,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public function toArray(): array
|
|
69
|
+
{
|
|
70
|
+
return array_filter([
|
|
71
|
+
'id' => $this->id,
|
|
72
|
+
'name' => $this->name,
|
|
73
|
+
'slug' => $this->slug,
|
|
74
|
+
'created_at' => $this->createdAt?->format(\DateTimeInterface::RFC3339_EXTENDED),
|
|
75
|
+
], fn ($v) => $v !== null);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public function jsonSerialize(): array
|
|
79
|
+
{
|
|
80
|
+
return $this->toArray();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Enum Pattern
|
|
86
|
+
|
|
87
|
+
PHP 8.1+ backed enums:
|
|
88
|
+
|
|
89
|
+
```php
|
|
90
|
+
<?php
|
|
91
|
+
|
|
92
|
+
namespace WorkOS\Enums;
|
|
93
|
+
|
|
94
|
+
enum OrganizationStatus: string
|
|
95
|
+
{
|
|
96
|
+
case Active = 'active';
|
|
97
|
+
case Inactive = 'inactive';
|
|
98
|
+
|
|
99
|
+
public static function tryFromValue(string $value): self|string
|
|
100
|
+
{
|
|
101
|
+
return self::tryFrom($value) ?? $value;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Resource Pattern
|
|
107
|
+
|
|
108
|
+
Resource classes with typed methods, injected HTTP client:
|
|
109
|
+
|
|
110
|
+
```php
|
|
111
|
+
<?php
|
|
112
|
+
|
|
113
|
+
namespace WorkOS\Resources;
|
|
114
|
+
|
|
115
|
+
use WorkOS\HttpClient;
|
|
116
|
+
use WorkOS\Models\Organization;
|
|
117
|
+
use WorkOS\PaginatedResponse;
|
|
118
|
+
use WorkOS\RequestOptions;
|
|
119
|
+
|
|
120
|
+
class Organizations
|
|
121
|
+
{
|
|
122
|
+
public function __construct(
|
|
123
|
+
private readonly HttpClient $client,
|
|
124
|
+
) {}
|
|
125
|
+
|
|
126
|
+
public function get(string $id, ?RequestOptions $options = null): Organization
|
|
127
|
+
{
|
|
128
|
+
$response = $this->client->request(
|
|
129
|
+
method: 'GET',
|
|
130
|
+
path: "organizations/{$id}",
|
|
131
|
+
options: $options,
|
|
132
|
+
);
|
|
133
|
+
return Organization::fromArray($response);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public function list(
|
|
137
|
+
?int $limit = null,
|
|
138
|
+
?string $after = null,
|
|
139
|
+
?RequestOptions $options = null,
|
|
140
|
+
): PaginatedResponse
|
|
141
|
+
{
|
|
142
|
+
$response = $this->client->request(
|
|
143
|
+
method: 'GET',
|
|
144
|
+
path: 'organizations',
|
|
145
|
+
query: array_filter([
|
|
146
|
+
'limit' => $limit,
|
|
147
|
+
'after' => $after,
|
|
148
|
+
], fn ($v) => $v !== null),
|
|
149
|
+
options: $options,
|
|
150
|
+
);
|
|
151
|
+
return PaginatedResponse::fromArray($response, Organization::class);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Client Architecture
|
|
157
|
+
|
|
158
|
+
Main client with resource accessors:
|
|
159
|
+
|
|
160
|
+
```php
|
|
161
|
+
<?php
|
|
162
|
+
|
|
163
|
+
namespace WorkOS;
|
|
164
|
+
|
|
165
|
+
class WorkOS
|
|
166
|
+
{
|
|
167
|
+
private HttpClient $httpClient;
|
|
168
|
+
private ?Resources\Organizations $organizations = null;
|
|
169
|
+
|
|
170
|
+
public function __construct(
|
|
171
|
+
string $apiKey = null,
|
|
172
|
+
string $baseUrl = 'https://api.workos.com',
|
|
173
|
+
int $timeout = 60,
|
|
174
|
+
int $maxRetries = 3,
|
|
175
|
+
) {
|
|
176
|
+
$apiKey ??= getenv('WORKOS_API_KEY') ?: '';
|
|
177
|
+
$this->httpClient = new HttpClient($apiKey, $baseUrl, $timeout, $maxRetries);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public function organizations(): Resources\Organizations
|
|
181
|
+
{
|
|
182
|
+
return $this->organizations ??= new Resources\Organizations($this->httpClient);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Error Handling
|
|
188
|
+
|
|
189
|
+
Exception hierarchy extending a base `ApiException`:
|
|
190
|
+
|
|
191
|
+
```php
|
|
192
|
+
<?php
|
|
193
|
+
|
|
194
|
+
namespace WorkOS\Exceptions;
|
|
195
|
+
|
|
196
|
+
class ApiException extends \Exception { /* status_code, request_id, etc. */ }
|
|
197
|
+
class AuthenticationException extends ApiException {}
|
|
198
|
+
class BadRequestException extends ApiException {}
|
|
199
|
+
class NotFoundException extends ApiException {}
|
|
200
|
+
class UnprocessableEntityException extends ApiException {}
|
|
201
|
+
class RateLimitExceededException extends ApiException {}
|
|
202
|
+
class ServerException extends ApiException {}
|
|
203
|
+
class ConfigurationException extends \Exception {}
|
|
204
|
+
class ConnectionException extends \Exception {}
|
|
205
|
+
class TimeoutException extends \Exception {}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Pagination
|
|
209
|
+
|
|
210
|
+
Generic paginated response with auto-iteration:
|
|
211
|
+
|
|
212
|
+
```php
|
|
213
|
+
<?php
|
|
214
|
+
|
|
215
|
+
namespace WorkOS;
|
|
216
|
+
|
|
217
|
+
class PaginatedResponse implements \IteratorAggregate
|
|
218
|
+
{
|
|
219
|
+
public function __construct(
|
|
220
|
+
public readonly array $data,
|
|
221
|
+
public readonly array $listMetadata,
|
|
222
|
+
private readonly ?\Closure $fetchPage = null,
|
|
223
|
+
) {}
|
|
224
|
+
|
|
225
|
+
public function hasMore(): bool { return ($this->listMetadata['after'] ?? null) !== null; }
|
|
226
|
+
|
|
227
|
+
public function getIterator(): \Generator
|
|
228
|
+
{
|
|
229
|
+
$page = $this;
|
|
230
|
+
while (true) {
|
|
231
|
+
yield from $page->data;
|
|
232
|
+
if (!$page->hasMore() || $page->fetchPage === null) break;
|
|
233
|
+
$page = ($page->fetchPage)(['after' => $page->listMetadata['after']]);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Retry Logic
|
|
240
|
+
|
|
241
|
+
Exponential backoff with jitter. Retryable statuses: 429, 500, 502, 503, 504. Respects `Retry-After` header.
|
|
242
|
+
|
|
243
|
+
## Testing
|
|
244
|
+
|
|
245
|
+
PHPUnit with Guzzle `MockHandler`:
|
|
246
|
+
|
|
247
|
+
```php
|
|
248
|
+
<?php
|
|
249
|
+
|
|
250
|
+
namespace Tests\Resources;
|
|
251
|
+
|
|
252
|
+
use GuzzleHttp\Handler\MockHandler;
|
|
253
|
+
use GuzzleHttp\HandlerStack;
|
|
254
|
+
use GuzzleHttp\Psr7\Response;
|
|
255
|
+
use PHPUnit\Framework\TestCase;
|
|
256
|
+
use WorkOS\WorkOS;
|
|
257
|
+
|
|
258
|
+
class OrganizationsTest extends TestCase
|
|
259
|
+
{
|
|
260
|
+
public function testGet(): void
|
|
261
|
+
{
|
|
262
|
+
$fixture = json_decode(file_get_contents(__DIR__ . '/../Fixtures/organization.json'), true);
|
|
263
|
+
$mock = new MockHandler([new Response(200, [], json_encode($fixture))]);
|
|
264
|
+
$client = new WorkOS(apiKey: 'test', handler: HandlerStack::create($mock));
|
|
265
|
+
|
|
266
|
+
$result = $client->organizations()->get('org_01234');
|
|
267
|
+
$this->assertInstanceOf(\WorkOS\Models\Organization::class, $result);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Structural Guidelines
|
|
273
|
+
|
|
274
|
+
| Category | Choice |
|
|
275
|
+
| ------------------ | -------------------------- |
|
|
276
|
+
| PHP Version | 8.2+ |
|
|
277
|
+
| HTTP Client | Guzzle 7 |
|
|
278
|
+
| Testing | PHPUnit 11 |
|
|
279
|
+
| HTTP Mocking | Guzzle MockHandler |
|
|
280
|
+
| Documentation | PHPDoc |
|
|
281
|
+
| Type Signatures | Native type hints + PHPDoc |
|
|
282
|
+
| Linting/Formatting | PHP CS Fixer |
|
|
283
|
+
| JSON Parsing | Native json_decode/encode |
|
|
284
|
+
| Package Manager | Composer |
|
|
285
|
+
| Build Tool | N/A (interpreted) |
|
|
286
|
+
|
|
287
|
+
## Directory Structure
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
src/
|
|
291
|
+
├── {Namespace}.php # Main client class
|
|
292
|
+
├── HttpClient.php # HTTP client with retry logic
|
|
293
|
+
├── PaginatedResponse.php # Cursor pagination
|
|
294
|
+
├── RequestOptions.php # Per-request options
|
|
295
|
+
├── Enums/
|
|
296
|
+
│ └── {EnumName}.php
|
|
297
|
+
├── Models/
|
|
298
|
+
│ └── {ModelName}.php
|
|
299
|
+
├── Resources/
|
|
300
|
+
│ └── {ServiceName}.php
|
|
301
|
+
└── Exceptions/
|
|
302
|
+
├── ApiException.php
|
|
303
|
+
├── AuthenticationException.php
|
|
304
|
+
└── ...
|
|
305
|
+
tests/
|
|
306
|
+
├── Fixtures/
|
|
307
|
+
│ └── {model_name}.json
|
|
308
|
+
├── Resources/
|
|
309
|
+
│ └── {ServiceName}Test.php
|
|
310
|
+
├── Models/
|
|
311
|
+
│ └── {ModelName}Test.php
|
|
312
|
+
└── ClientTest.php
|
|
313
|
+
composer.json
|
|
314
|
+
phpunit.xml
|
|
315
|
+
```
|