Skip to content

Commit

Permalink
add hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
tatarco committed Jan 29, 2025
1 parent 0668205 commit 6f60343
Show file tree
Hide file tree
Showing 23 changed files with 259 additions and 74 deletions.
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions .idea/php-novu.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions .idea/php.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 32 additions & 17 deletions .speakeasy/gen.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .speakeasy/gen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ generation:
oAuth2ClientCredentialsEnabled: true
oAuth2PasswordEnabled: true
php:
version: 0.0.1
version: 0.0.3
additionalDependencies:
autoload: {}
autoload-dev: {}
Expand Down
12 changes: 8 additions & 4 deletions .speakeasy/workflow.lock
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
speakeasyVersion: 1.469.0
speakeasyVersion: 1.477.0
sources:
novu-OAS:
sourceNamespace: novu-oas
sourceRevisionDigest: sha256:21367ef75f16ed5cfdf8972684fbe3671307fe5f95f10842295478088904d0a5
sourceRevisionDigest: sha256:afca4841be828649b4401bceecbfb11268e27452ae2f0083565fd52186c41c01
sourceBlobDigest: sha256:ba8ff28975436bfaa7b97c66c2a878486ea83454788feffc7c3b3b65390c3add
tags:
- latest
targets:
novu:
source: novu-OAS
sourceNamespace: novu-oas
sourceRevisionDigest: sha256:21367ef75f16ed5cfdf8972684fbe3671307fe5f95f10842295478088904d0a5
sourceRevisionDigest: sha256:afca4841be828649b4401bceecbfb11268e27452ae2f0083565fd52186c41c01
sourceBlobDigest: sha256:ba8ff28975436bfaa7b97c66c2a878486ea83454788feffc7c3b3b65390c3add
codeSamplesNamespace: novu-oas-php-code-samples
codeSamplesRevisionDigest: sha256:c8e706ea02db24c7e018e31e90f32932d1c676a7cf3d68ebf7ab919538531d46
codeSamplesRevisionDigest: sha256:8f36789a8fc87106bddfa70fd57230b2f140ebeeb947f73b5d1478ee01c26b29
workflow:
workflowVersion: 1.0.0
speakeasyVersion: latest
Expand All @@ -27,6 +27,10 @@ workflow:
novu:
target: php
source: novu-OAS
publish:
packagist:
username: novuhq
token: $packagist_token
codeSamples:
registry:
location: registry.speakeasyapi.dev/novu/novu/novu-oas-php-code-samples
Expand Down
25 changes: 2 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,32 +43,11 @@ For more information about the API: [Novu Documentation](https://docs.novu.co)
<!-- Start SDK Installation [installation] -->
## SDK Installation

> [!TIP]
> To finish publishing your SDK you must [run your first generation action](https://www.speakeasy.com/docs/github-setup#step-by-step-guide).

The SDK relies on [Composer](https://getcomposer.org/) to manage its dependencies.

To install the SDK first add the below to your `composer.json` file:

```json
{
"repositories": [
{
"type": "github",
"url": "<UNSET>.git"
}
],
"require": {
"novuhq/novu": "*"
}
}
```

Then run the following command:

To install the SDK and add it as a dependency to an existing `composer.json` file:
```bash
composer update
composer require "novuhq/novu"
```
<!-- End SDK Installation [installation] -->

Expand Down
2 changes: 1 addition & 1 deletion docs/Models/Components/To.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The recipients list of people who will receive the notification.

```php
/**
* @var array<mixed>
* @var array<Components\SubscriberPayloadDto|Components\TopicPayloadDto|string>
*/
array $value = /* values here */
```
Expand Down
12 changes: 6 additions & 6 deletions src/Hooks/HookRegistration.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ class HookRegistration
*/
public static function initHooks(Hooks $hooks): void
{
// $myHook = new MyHook();

// $hooks->registerSDKInitHook($myHook);
// $hooks->registerBeforeRequestHook($myHook);
// $hooks->registerAfterSuccessHook($myHook);
// $hooks->registerAfterErrorHook($myHook);
$myHook = new NovuHooks();
//
// $hooks->registerSDKInitHook($myHook);
$hooks->registerBeforeRequestHook($myHook);
$hooks->registerAfterSuccessHook($myHook);
// $hooks->registerAfterErrorHook($myHook);
}
}
111 changes: 111 additions & 0 deletions src/Hooks/NovuHooks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

declare(strict_types=1);

namespace novu\Hooks;

use Exception;
use GuzzleHttp\Psr7\Request;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

class NovuHooks implements
BeforeRequestHook,
AfterSuccessHook
{
private $mutex = false;

Check failure on line 16 in src/Hooks/NovuHooks.php

View workflow job for this annotation

GitHub Actions / generate / Generate Target

Property novu\Hooks\NovuHooks::$mutex has no type specified.

Check failure on line 16 in src/Hooks/NovuHooks.php

View workflow job for this annotation

GitHub Actions / generate / Generate Target

Property novu\Hooks\NovuHooks::$mutex has no type specified.


/**
* Generate a cryptographically secure random string
*/
private function generateSecureRandomString(int $length): string
{
$charset = 'abcdefghijklmnopqrstuvwxyz0123456789';
$result = '';
$charsetLength = strlen($charset);

for ($i = 0; $i < $length; $i++) {
$result .= $charset[random_int(0, $charsetLength - 1)];
}

return $result;
}

/**
* Generate a unique idempotency key
*/
private function generateIdempotencyKey(): string
{
// Use a mutex-like mechanism (simple lock)
if ($this->mutex) {
usleep(1000); // Small delay to prevent collision
}
$this->mutex = true;

$timestamp = (int)(microtime(true) * 1000);
$randomStr = $this->generateSecureRandomString(9);

$this->mutex = false;
return (string)$timestamp . $randomStr;
}

public function beforeRequest(BeforeRequestContext $context, RequestInterface $request): RequestInterface
{
$authKey = 'Authorization';
$idempotencyKey = 'Idempotency-Key';
$apiKeyPrefix = 'ApiKey';

// Ensure Authorization header is prefixed with ApiKey if needed
$authHeader = $request->getHeaderLine($authKey);
if ($authHeader && !str_starts_with($authHeader, $apiKeyPrefix)) {
$request = $request->withHeader($authKey, "$apiKeyPrefix $authHeader");
}

// Add idempotency key if not present
if (!$request->hasHeader($idempotencyKey)) {
try {
$key = $this->generateIdempotencyKey();
$request = $request->withHeader($idempotencyKey, $key);
} catch (Exception $e) {
throw new Exception("Failed to generate idempotency key: " . $e->getMessage());
}
}

return $request;
}

public function afterSuccess(AfterSuccessContext $context, ResponseInterface $response): ResponseInterface
{
// Check content type
$contentType = $response->getHeaderLine('Content-Type');
if (!$response->getBody() || !str_contains($contentType, 'application/json')) {

Check failure on line 82 in src/Hooks/NovuHooks.php

View workflow job for this annotation

GitHub Actions / generate / Generate Target

Negated boolean expression is always false.

Check failure on line 82 in src/Hooks/NovuHooks.php

View workflow job for this annotation

GitHub Actions / generate / Generate Target

Negated boolean expression is always false.
return $response;
}

// Read the body
$bodyContent = $response->getBody()->getContents();

// If body is empty, return original response
if (empty($bodyContent)) {
return $response;
}

// Try to parse JSON
$jsonResponse = json_decode($bodyContent, true);
if (json_last_error() !== JSON_ERROR_NONE) {
// If not JSON, restore original body
return $response;
}

// Check if response has a 'data' key
if (isset($jsonResponse['data'])) {
$newBody = json_encode($jsonResponse['data']);
$response->getBody()->rewind();
$response->getBody()->write($newBody);

Check failure on line 105 in src/Hooks/NovuHooks.php

View workflow job for this annotation

GitHub Actions / generate / Generate Target

Parameter #1 $string of method Psr\Http\Message\StreamInterface::write() expects string, string|false given.

Check failure on line 105 in src/Hooks/NovuHooks.php

View workflow job for this annotation

GitHub Actions / generate / Generate Target

Parameter #1 $string of method Psr\Http\Message\StreamInterface::write() expects string, string|false given.
$response->getBody()->rewind();
}

return $response;
}
}
6 changes: 3 additions & 3 deletions src/Models/Components/CreateSubscriberRequestDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ class CreateSubscriberRequestDto
/**
* An optional payload object that can contain any properties.
*
* @var ?array<string, mixed> $data
* @var ?array<string, string|array<string>|bool|float> $data
*/
#[\Speakeasy\Serializer\Annotation\SerializedName('data')]
#[\Speakeasy\Serializer\Annotation\Type('array<string, mixed>|null')]
#[\Speakeasy\Serializer\Annotation\Type('array<string, string|array<string>|bool|float>|null')]
#[\Speakeasy\Serializer\Annotation\SkipWhenNull]
public ?array $data = null;

Expand All @@ -101,7 +101,7 @@ class CreateSubscriberRequestDto
* @param ?string $phone
* @param ?string $avatar
* @param ?string $locale
* @param ?array<string, mixed> $data
* @param ?array<string, string|array<string>|bool|float> $data
* @param ?array<SubscriberChannelDto> $channels
*/
public function __construct(string $subscriberId, ?string $email = null, ?string $firstName = null, ?string $lastName = null, ?string $phone = null, ?string $avatar = null, ?string $locale = null, ?array $data = null, ?array $channels = null)
Expand Down
2 changes: 1 addition & 1 deletion src/Models/Components/MarkAllMessageAsRequestDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class MarkAllMessageAsRequestDto
* @var string|array<string>|null $feedIdentifier
*/
#[\Speakeasy\Serializer\Annotation\SerializedName('feedIdentifier')]
#[\Speakeasy\Serializer\Annotation\Type('string|array<string>')]
#[\Speakeasy\Serializer\Annotation\Type('string|array<string>|null')]
#[\Speakeasy\Serializer\Annotation\SkipWhenNull]
public string|array|null $feedIdentifier = null;

Expand Down
2 changes: 1 addition & 1 deletion src/Models/Components/NotificationStepData.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class NotificationStepData
* @var DigestRegularMetadata|DigestTimedMetadata|DelayRegularMetadata|DelayScheduledMetadata|null $metadata
*/
#[\Speakeasy\Serializer\Annotation\SerializedName('metadata')]
#[\Speakeasy\Serializer\Annotation\Type('\novu\Models\Components\DigestRegularMetadata|\novu\Models\Components\DigestTimedMetadata|\novu\Models\Components\DelayRegularMetadata|\novu\Models\Components\DelayScheduledMetadata')]
#[\Speakeasy\Serializer\Annotation\Type('\novu\Models\Components\DigestRegularMetadata|\novu\Models\Components\DigestTimedMetadata|\novu\Models\Components\DelayRegularMetadata|\novu\Models\Components\DelayScheduledMetadata|null')]
#[\Speakeasy\Serializer\Annotation\SkipWhenNull]
public DigestRegularMetadata|DigestTimedMetadata|DelayRegularMetadata|DelayScheduledMetadata|null $metadata = null;

Expand Down
2 changes: 1 addition & 1 deletion src/Models/Components/NotificationStepDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class NotificationStepDto
* @var DigestRegularMetadata|DigestTimedMetadata|DelayRegularMetadata|DelayScheduledMetadata|null $metadata
*/
#[\Speakeasy\Serializer\Annotation\SerializedName('metadata')]
#[\Speakeasy\Serializer\Annotation\Type('\novu\Models\Components\DigestRegularMetadata|\novu\Models\Components\DigestTimedMetadata|\novu\Models\Components\DelayRegularMetadata|\novu\Models\Components\DelayScheduledMetadata')]
#[\Speakeasy\Serializer\Annotation\Type('\novu\Models\Components\DigestRegularMetadata|\novu\Models\Components\DigestTimedMetadata|\novu\Models\Components\DelayRegularMetadata|\novu\Models\Components\DelayScheduledMetadata|null')]
#[\Speakeasy\Serializer\Annotation\SkipWhenNull]
public DigestRegularMetadata|DigestTimedMetadata|DelayRegularMetadata|DelayScheduledMetadata|null $metadata = null;

Expand Down
6 changes: 3 additions & 3 deletions src/Models/Components/SubscriberPayloadDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ class SubscriberPayloadDto
/**
* An optional payload object that can contain any properties.
*
* @var ?array<string, mixed> $data
* @var ?array<string, string|array<string>|bool|float> $data
*/
#[\Speakeasy\Serializer\Annotation\SerializedName('data')]
#[\Speakeasy\Serializer\Annotation\Type('array<string, mixed>|null')]
#[\Speakeasy\Serializer\Annotation\Type('array<string, string|array<string>|bool|float>|null')]
#[\Speakeasy\Serializer\Annotation\SkipWhenNull]
public ?array $data = null;

Expand All @@ -101,7 +101,7 @@ class SubscriberPayloadDto
* @param ?string $phone
* @param ?string $avatar
* @param ?string $locale
* @param ?array<string, mixed> $data
* @param ?array<string, string|array<string>|bool|float> $data
* @param ?array<SubscriberChannelDto> $channels
*/
public function __construct(string $subscriberId, ?string $email = null, ?string $firstName = null, ?string $lastName = null, ?string $phone = null, ?string $avatar = null, ?string $locale = null, ?array $data = null, ?array $channels = null)
Expand Down
10 changes: 5 additions & 5 deletions src/Models/Components/TriggerEventRequestDto.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ class TriggerEventRequestDto
/**
* The recipients list of people who will receive the notification.
*
* @var array<mixed>|string|SubscriberPayloadDto|TopicPayloadDto $to
* @var array<SubscriberPayloadDto|TopicPayloadDto|string>|string|SubscriberPayloadDto|TopicPayloadDto $to
*/
#[\Speakeasy\Serializer\Annotation\SerializedName('to')]
#[\Speakeasy\Serializer\Annotation\Type('array<mixed>|string|\novu\Models\Components\SubscriberPayloadDto|\novu\Models\Components\TopicPayloadDto')]
#[\Speakeasy\Serializer\Annotation\Type('array<\novu\Models\Components\SubscriberPayloadDto|\novu\Models\Components\TopicPayloadDto|string>|string|\novu\Models\Components\SubscriberPayloadDto|\novu\Models\Components\TopicPayloadDto')]
public array|string|SubscriberPayloadDto|TopicPayloadDto $to;

/**
Expand Down Expand Up @@ -80,7 +80,7 @@ class TriggerEventRequestDto
* @var string|SubscriberPayloadDto|null $actor
*/
#[\Speakeasy\Serializer\Annotation\SerializedName('actor')]
#[\Speakeasy\Serializer\Annotation\Type('string|\novu\Models\Components\SubscriberPayloadDto')]
#[\Speakeasy\Serializer\Annotation\Type('string|\novu\Models\Components\SubscriberPayloadDto|null')]
#[\Speakeasy\Serializer\Annotation\SkipWhenNull]
public string|SubscriberPayloadDto|null $actor = null;

Expand All @@ -92,7 +92,7 @@ class TriggerEventRequestDto
* @var string|TenantPayloadDto|null $tenant
*/
#[\Speakeasy\Serializer\Annotation\SerializedName('tenant')]
#[\Speakeasy\Serializer\Annotation\Type('string|\novu\Models\Components\TenantPayloadDto')]
#[\Speakeasy\Serializer\Annotation\Type('string|\novu\Models\Components\TenantPayloadDto|null')]
#[\Speakeasy\Serializer\Annotation\SkipWhenNull]
public string|TenantPayloadDto|null $tenant = null;

Expand All @@ -108,7 +108,7 @@ class TriggerEventRequestDto

/**
* @param string $name
* @param array<mixed>|string|SubscriberPayloadDto|TopicPayloadDto $to
* @param array<SubscriberPayloadDto|TopicPayloadDto|string>|string|SubscriberPayloadDto|TopicPayloadDto $to
* @param ?array<string, mixed> $payload
* @param ?string $bridgeUrl
* @param ?array<string, array<string, mixed>> $overrides
Expand Down
Loading

0 comments on commit 6f60343

Please sign in to comment.